package internal import ( "io/fs" "log" "net/http" "os" "runtime" "time" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ EnableCompression: true, HandshakeTimeout: time.Second * 2, } type adminHandler struct { Cache Storage EventSubscriber EventPublisher *RuleEngine h http.Handler } func NewAdminHandler(c Cache, s Storage, re *RuleEngine, content fs.FS) http.Handler { handler := chi.NewRouter() a := &adminHandler{ Cache: c, Storage: s, RuleEngine: re, h: handler, } handler.Use(middleware.RequestID) handler.Use(middleware.RealIP) handler.Use(middleware.Logger) handler.Use(middleware.Recoverer) handler.Route("/api/v1", func(r chi.Router) { r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"http://*", "https://*"}, AllowedMethods: []string{"GET", "PUT", "DELETE", "POST", "OPTIONS"}, AllowedHeaders: []string{"Content-Type", "Accept"}, AllowCredentials: false, MaxAge: 300, })) r.Use(middleware.AllowContentType("application/json; utf-8", "application/json")) r.Use(middleware.SetHeader("Content-Type", "application/json; utf-8")) r.Use(middleware.Timeout(time.Second * 5)) r.Get("/metrics/log", RestHandler(a.getLog).ToHF()) r.Get("/metrics/stats", RestHandler(a.getStats).ToHF()) r.Put("/rules", RestHandler(a.createRule).ToHF()) r.Get("/rules", RestHandler(a.getRules).ToHF()) r.Get("/rules/{id:[0-9]+}", RestHandler(a.getRule).ToHF()) r.Post("/rules/{id:[0-9]+}", RestHandler(a.updateRule).ToHF()) r.Delete("/rules/{id:[0-9]+}", RestHandler(a.deleteRule).ToHF()) r.Put("/recursors", RestHandler(a.addRecursor).ToHF()) r.Get("/recursors", RestHandler(a.getRecursors).ToHF()) r.Get("/recursors/{id:[0-9]+}", RestHandler(a.getRecursor).ToHF()) r.Delete("/recursor/{id:[0-9]+}", RestHandler(a.deleteRecursor).ToHF()) r.HandleFunc("/signal", a.signal) // r.Put("/rules/lists", a.addRulelist) // r.Get("/rules/lists", a.getRuleLists) // r.Post("/rules/lists/reload/{id}", a.reloadRuleLists) // r.Delete("/rules/lists/{id}", a.deleteRuleList) // r.Get("/updates", RestHandler(a.getStats).ToHF()) // r.Delete("/cache/purgeall", RestHandler(a.purgeAll).ToHF()) // r.Delete("/cache/purge", a.purgeKey) // r.Get("/cache", a.getCacheContents) }) fs := http.FS(content) httpFileServer := http.FileServer(fs) handler.Handle("/*", http.StripPrefix("/", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { f, err := content.Open(r.URL.Path) if os.IsNotExist(err) { r.URL.Path = "/" } if err == nil { f.Close() } log.Printf("%s - err: %v", r.URL.Path, err) httpFileServer.ServeHTTP(rw, r) }))) return a } func (a *adminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { a.h.ServeHTTP(w, r) } func (a *adminHandler) signal(w http.ResponseWriter, r *http.Request) { c, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Print("could not upgrade to a websocket:", err) return } defer c.Close() for { runtime.Gosched() // send any updates that come through to the client } }