package main import ( "context" "log" "time" "github.com/gin-gonic/gin" "kefu-sys/server/internal/config" "kefu-sys/server/internal/handler" "kefu-sys/server/internal/middleware" "kefu-sys/server/internal/model" "kefu-sys/server/internal/storage" "kefu-sys/server/internal/ws" ) func main() { cfg := config.Load() // 初始化数据库 model.InitDB(cfg.Database.DSN()) // 初始化 JWT middleware.InitJWT(cfg.JWT.Secret) // 对象存储(MinIO / S3 兼容) store, err := storage.NewS3(cfg.Storage) if err != nil { log.Fatalf("对象存储初始化失败: %v", err) } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := store.EnsureBucket(ctx); err != nil { log.Printf("警告: 确保存储桶失败(可稍后启动 MinIO): %v", err) } else { log.Printf("对象存储就绪: %s bucket=%s public=%s", cfg.Storage.Endpoint, cfg.Storage.Bucket, cfg.Storage.PublicBase) } // 启动 WebSocket Hub go ws.DefaultHub.Run() // 设置 Gin 模式 gin.SetMode(cfg.Server.Mode) r := gin.Default() // CORS r.Use(func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS") c.Header("Access-Control-Allow-Headers", "Content-Type,Authorization,X-Visitor-Token") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() }) // 健康检查 r.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{"status": "ok"}) }) // 注册路由 handler.SetupRoutes(r, store, cfg.Storage) log.Printf("客服云服务启动在 :%s", cfg.Server.Port) if err := r.Run(":" + cfg.Server.Port); err != nil { log.Fatalf("启动失败: %v", err) } }