package goblocks import ( "net/http" "os" "path/filepath" "slices" "strings" ) type Middleware func(http.Handler) http.Handler type Router struct { globalChain []Middleware routeChain []Middleware isSub bool *http.ServeMux } func newRouter() *Router { return &Router{ServeMux: http.NewServeMux()} } func (r *Router) Use(mw ...Middleware) { if r.isSub { r.routeChain = append(r.routeChain, mw...) } else { r.globalChain = append(r.globalChain, mw...) } } func (r *Router) Group(basePath string, fn func(r *Router)) { sub := &Router{ ServeMux: r.ServeMux, routeChain: slices.Clone(r.routeChain), isSub: true, } // AƱadir middleware para manejar el basePath sub.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if !strings.HasPrefix(req.URL.Path, basePath) { http.NotFound(w, req) return } req.URL.Path = strings.TrimPrefix(req.URL.Path, basePath) next.ServeHTTP(w, req) }) }) fn(sub) } func (r *Router) Static(urlPrefix, dir string) { urlPrefix = strings.TrimSuffix(urlPrefix, "/") fileServer := http.FileServer(http.Dir(dir)) fs := http.StripPrefix(urlPrefix, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { fullPath := filepath.Join(dir, req.URL.Path) info, err := os.Stat(fullPath) if err != nil { http.NotFound(w, req) return } if info.IsDir() { http.NotFound(w, req) return } w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") fileServer.ServeHTTP(w, req) })) r.Handle(urlPrefix+"/", fs) } func (r *Router) HandleFunc(pattern string, h http.HandlerFunc) { r.Handle(pattern, h) } func (r *Router) Handle(pattern string, h http.Handler) { chain := slices.Clone(r.routeChain) slices.Reverse(chain) for _, mw := range chain { h = mw(h) } r.ServeMux.Handle(pattern, h) } func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { h := http.Handler(r.ServeMux) chain := slices.Clone(r.globalChain) slices.Reverse(chain) for _, mw := range chain { h = mw(h) } h.ServeHTTP(w, req) }