You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.2 KiB

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)
// TODO: smarter way https://github.com/go-chi/chi/issues/403
handler.Route("/api/v1", func(r chi.Router) {
r.Use(middleware.AllowContentType("application/json; utf-8", "application/json"))
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.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
}
}