Files
FileRelay/main.go

122 lines
4.0 KiB
Go

package main
import (
_ "FileRelay/docs"
"FileRelay/internal/api/admin"
"FileRelay/internal/api/middleware"
"FileRelay/internal/api/public"
"FileRelay/internal/bootstrap"
"FileRelay/internal/config"
"FileRelay/internal/model"
"FileRelay/internal/task"
"context"
"fmt"
"log"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
// @title 文件暂存柜 API
// @version 1.0
// @description 自托管的文件暂存柜后端系统 API 文档
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @BasePath /
// @securityDefinitions.apikey AdminAuth
// @in header
// @name Authorization
// @description Type "Bearer <JWT-Token>" or "Bearer <API-Token>" to authenticate. API Token must have 'admin' scope.
// @securityDefinitions.apikey APITokenAuth
// @in header
// @name Authorization
// @description Type "Bearer <API-Token>" to authenticate. Required scope depends on the endpoint.
func main() {
// 1. 加载配置
if err := config.LoadConfig("config/config.yaml"); err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// 2. 初始化
bootstrap.InitDB()
// 3. 启动清理任务
cleaner := task.NewCleaner()
go cleaner.Start(context.Background())
// 4. 设置路由
r := gin.Default()
// 配置更完善的 CORS
corsConfig := cors.DefaultConfig()
corsConfig.AllowAllOrigins = true
corsConfig.AllowHeaders = append(corsConfig.AllowHeaders, "Authorization", "Accept", "X-Requested-With")
corsConfig.AllowMethods = append(corsConfig.AllowMethods, "OPTIONS")
r.Use(cors.New(corsConfig))
// Swagger 文档
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
// 公共接口
uploadHandler := public.NewUploadHandler()
pickupHandler := public.NewPickupHandler()
publicConfigHandler := public.NewConfigHandler()
api := r.Group("/api")
{
api.GET("/config", publicConfigHandler.GetPublicConfig)
// 统一使用 /batches 作为资源路径
api.POST("/batches", middleware.APITokenAuth(model.ScopeUpload, !config.GlobalConfig.Upload.RequireToken), uploadHandler.Upload)
api.POST("/batches/text", middleware.APITokenAuth(model.ScopeUpload, !config.GlobalConfig.Upload.RequireToken), uploadHandler.UploadText)
api.GET("/batches/:pickup_code", middleware.PickupRateLimit(), middleware.APITokenAuth(model.ScopePickup, true), pickupHandler.Pickup)
api.GET("/batches/:pickup_code/download", middleware.APITokenAuth(model.ScopePickup, true), pickupHandler.DownloadBatch)
// 文件下载保持 /files/:id/download 风格
api.GET("/files/:file_id/download", middleware.APITokenAuth(model.ScopePickup, true), pickupHandler.DownloadFile)
// 保持旧路由兼容性 (可选,但为了平滑过渡通常建议保留一段时间或直接更新)
// 这里根据需求“调整不符合规范的”,我将直接采用新路由
}
// 管理员接口
authHandler := admin.NewAuthHandler()
batchHandler := admin.NewBatchHandler()
tokenHandler := admin.NewTokenHandler()
configHandler := admin.NewConfigHandler()
r.POST("/admin/login", authHandler.Login)
adm := r.Group("/admin")
adm.Use(middleware.AdminAuth())
{
adm.GET("/config", configHandler.GetConfig)
adm.PUT("/config", configHandler.UpdateConfig)
adm.GET("/batches", batchHandler.ListBatches)
adm.GET("/batches/:batch_id", batchHandler.GetBatch)
adm.PUT("/batches/:batch_id", batchHandler.UpdateBatch)
adm.DELETE("/batches/:batch_id", batchHandler.DeleteBatch)
adm.GET("/api-tokens", tokenHandler.ListTokens)
adm.POST("/api-tokens", tokenHandler.CreateToken)
adm.DELETE("/api-tokens/:id", tokenHandler.DeleteToken)
adm.POST("/api-tokens/:id/revoke", tokenHandler.RevokeToken)
}
// 5. 运行
port := 8080
fmt.Printf("Server is running on port %d\n", port)
r.Run(fmt.Sprintf(":%d", port))
}