package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" _ "carrotskin/docs" // Swagger文档 "carrotskin/internal/handler" "carrotskin/internal/middleware" "carrotskin/pkg/auth" "carrotskin/pkg/config" "carrotskin/pkg/database" "carrotskin/pkg/email" "carrotskin/pkg/logger" "carrotskin/pkg/redis" "carrotskin/pkg/storage" "github.com/gin-gonic/gin" "go.uber.org/zap" ) func main() { // 初始化配置 if err := config.Init(); err != nil { log.Fatalf("配置加载失败: %v", err) } cfg := config.MustGetConfig() // 初始化日志 if err := logger.Init(cfg.Log); err != nil { log.Fatalf("日志初始化失败: %v", err) } loggerInstance := logger.MustGetLogger() defer loggerInstance.Sync() // 初始化数据库 if err := database.Init(cfg.Database, loggerInstance); err != nil { loggerInstance.Fatal("数据库初始化失败", zap.Error(err)) } defer database.Close() // 执行数据库迁移 if err := database.AutoMigrate(loggerInstance); err != nil { loggerInstance.Fatal("数据库迁移失败", zap.Error(err)) } // 初始化JWT服务 if err := auth.Init(cfg.JWT); err != nil { loggerInstance.Fatal("JWT服务初始化失败", zap.Error(err)) } // 初始化Redis if err := redis.Init(cfg.Redis, loggerInstance); err != nil { loggerInstance.Fatal("Redis连接失败", zap.Error(err)) } defer redis.MustGetClient().Close() // 初始化对象存储 (RustFS - S3兼容) // 如果对象存储未配置或连接失败,记录警告但不退出(某些功能可能不可用) if err := storage.Init(cfg.RustFS); err != nil { loggerInstance.Warn("对象存储连接失败,某些功能可能不可用", zap.Error(err)) } else { loggerInstance.Info("对象存储连接成功") } // 初始化邮件服务 if err := email.Init(cfg.Email, loggerInstance); err != nil { loggerInstance.Fatal("邮件服务初始化失败", zap.Error(err)) } // 设置Gin模式 if cfg.Server.Mode == "production" { gin.SetMode(gin.ReleaseMode) } // 创建路由 router := gin.New() // 添加中间件 router.Use(middleware.Logger(loggerInstance)) router.Use(middleware.Recovery(loggerInstance)) router.Use(middleware.CORS()) // 注册路由 handler.RegisterRoutes(router) // 创建HTTP服务器 srv := &http.Server{ Addr: cfg.Server.Port, Handler: router, ReadTimeout: cfg.Server.ReadTimeout, WriteTimeout: cfg.Server.WriteTimeout, } // 启动服务器 go func() { loggerInstance.Info("服务器启动", zap.String("port", cfg.Server.Port)) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { loggerInstance.Fatal("服务器启动失败", zap.Error(err)) } }() // 等待中断信号优雅关闭 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit loggerInstance.Info("正在关闭服务器...") // 设置关闭超时 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { loggerInstance.Fatal("服务器强制关闭", zap.Error(err)) } loggerInstance.Info("服务器已关闭") }