package router import ( "time" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "sproutworkcollect-backend/internal/config" "sproutworkcollect-backend/internal/handler" "sproutworkcollect-backend/internal/middleware" "sproutworkcollect-backend/internal/service" ) // Setup creates and configures the Gin engine: middleware, services, handlers, and routes. func Setup(cfg *config.Config) *gin.Engine { if !cfg.Debug { gin.SetMode(gin.ReleaseMode) } r := gin.Default() // Allow files up to 32 MB to stay in memory; larger ones spill to temp disk files. // This keeps RAM usage bounded even for gigabyte-scale uploads. r.MaxMultipartMemory = 32 << 20 // 允许所有来源,并显式放开 Authorization 头,解决跨域访问后台接口时的预检失败问题。 corsCfg := cors.Config{ AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{ "Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With", }, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: false, MaxAge: 12 * time.Hour, } r.Use(cors.New(corsCfg)) // ─── Services ───────────────────────────────────────────────────────────── workSvc := service.NewWorkService(cfg) settingsSvc := service.NewSettingsService(cfg) rateLimiter := service.NewRateLimiter() // ─── Handlers ───────────────────────────────────────────────────────────── pub := handler.NewPublicHandler(workSvc, settingsSvc, rateLimiter) media := handler.NewMediaHandler(workSvc, rateLimiter) admin := handler.NewAdminHandler(workSvc) // ─── Public routes ──────────────────────────────────────────────────────── r.GET("/", func(c *gin.Context) { c.JSON(200, gin.H{ "service": "SproutWorkCollect API", "version": "v1", "endpoints": []string{"/api/settings", "/api/works", "/api/works/{work_id}", "/api/search", "/api/categories", "/api/like/{work_id}"}, }) }) api := r.Group("/api") { api.GET("/settings", pub.GetSettings) api.GET("/works", pub.GetWorks) api.GET("/works/:work_id", pub.GetWorkDetail) api.GET("/search", pub.SearchWorks) api.GET("/categories", pub.GetCategories) api.POST("/like/:work_id", pub.LikeWork) api.GET("/image/:work_id/:filename", media.ServeImage) api.GET("/video/:work_id/:filename", media.ServeVideo) api.GET("/download/:work_id/:platform/:filename", media.DownloadFile) } // ─── Admin routes (token-protected) ────────────────────────────────────── adm := api.Group("/admin", middleware.AdminAuth(cfg.AdminToken)) { adm.GET("/works", admin.GetWorks) adm.POST("/works", admin.CreateWork) adm.PUT("/works/:work_id", admin.UpdateWork) adm.DELETE("/works/:work_id", admin.DeleteWork) adm.POST("/upload/:work_id/:file_type", admin.UploadFile) adm.DELETE("/delete-file/:work_id/:file_type/:filename", admin.DeleteFile) } return r }