package router import ( "fmt" "html/template" "io/fs" "net/http" "net/url" "os" "path/filepath" "strings" "github.com/gin-gonic/gin" "github.com/labring/aiproxy/core/common/config" "github.com/labring/aiproxy/core/public" "github.com/sirupsen/logrus" ) func SetStaticFileRouter(router *gin.Engine) { router.SetHTMLTemplate( template.Must( template.New("").Funcs(router.FuncMap).ParseFS(public.Templates, "templates/*"), ), ) if config.DisableWeb { router.GET("/", func(ctx *gin.Context) { ctx.HTML(http.StatusOK, "index.tmpl", gin.H{ "URL": "https://github.com/labring/aiproxy", "INITIAL_COUNTDOWN": 15, }) }) return } if config.WebPath == "" { routerFs, ok := public.Public.(fs.ReadDirFS) if !ok { panic(fmt.Sprintf("public fs type error: %T, %v", public.Public, public.Public)) } err := initFSRouter(router, routerFs, ".") if err != nil { panic(err) } fs := http.FS(public.Public) router.NoRoute(newIndexNoRouteHandler(fs)) } else { absPath, err := filepath.Abs(config.WebPath) if err != nil { panic(err) } logrus.Infof("frontend file path: %s", absPath) routerFs, ok := os.DirFS(absPath).(fs.ReadDirFS) if !ok { panic(fmt.Sprintf("public fs type error: %T, %v", public.Public, public.Public)) } err = initFSRouter(router, routerFs, ".") if err != nil { panic(err) } router.NoRoute(newDynamicNoRouteHandler(http.Dir(absPath))) } } func checkNoRouteNotFound(req *http.Request) bool { if req.Method != http.MethodGet && req.Method != http.MethodHead { return true } if strings.HasPrefix(req.URL.Path, "/api") || strings.HasPrefix(req.URL.Path, "/mcp") || strings.HasPrefix(req.URL.Path, "/v1") { return true } return false } func newIndexNoRouteHandler(fs http.FileSystem) func(ctx *gin.Context) { return func(ctx *gin.Context) { if checkNoRouteNotFound(ctx.Request) { http.NotFound(ctx.Writer, ctx.Request) return } ctx.FileFromFS("", fs) } } func newDynamicNoRouteHandler(fs http.FileSystem) func(ctx *gin.Context) { fileServer := http.StripPrefix("/", http.FileServer(fs)) return func(c *gin.Context) { if checkNoRouteNotFound(c.Request) { http.NotFound(c.Writer, c.Request) return } f, err := fs.Open(c.Request.URL.Path) if err != nil { c.FileFromFS("", fs) return } f.Close() fileServer.ServeHTTP(c.Writer, c.Request) } } type staticFileFS interface { StaticFileFS(relativePath, filepath string, fs http.FileSystem) gin.IRoutes } func initFSRouter(e staticFileFS, f fs.ReadDirFS, path string) error { dirs, err := f.ReadDir(path) if err != nil { return err } for _, dir := range dirs { u, err := url.JoinPath(path, dir.Name()) if err != nil { return err } if dir.IsDir() { err = initFSRouter(e, f, u) if err != nil { return err } } else { e.StaticFileFS(u, u, http.FS(f)) } } return nil }