package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "carrotskin/internal/container" "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)) } // 初始化种子数据 if err := database.Seed(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兼容) var storageClient *storage.StorageClient if err := storage.Init(cfg.RustFS); err != nil { loggerInstance.Warn("对象存储连接失败,某些功能可能不可用", zap.Error(err)) } else { storageClient = storage.MustGetClient() loggerInstance.Info("对象存储连接成功") } // 初始化邮件服务 if err := email.Init(cfg.Email, loggerInstance); err != nil { loggerInstance.Fatal("邮件服务初始化失败", zap.Error(err)) } emailServiceInstance := email.MustGetService() // 创建依赖注入容器 c := container.NewContainer( database.MustGetDB(), redis.MustGetClient(), loggerInstance, auth.MustGetJWTService(), storageClient, emailServiceInstance, ) // 设置Gin模式 if cfg.Server.Mode == "production" { gin.SetMode(gin.ReleaseMode) } // 创建路由 router := gin.New() // 禁用自动重定向,允许API路径带或不带/结尾都能正常访问 router.RedirectTrailingSlash = false router.RedirectFixedPath = false // 添加中间件 router.Use(middleware.Logger(loggerInstance)) router.Use(middleware.Recovery(loggerInstance)) router.Use(middleware.CORS()) // 使用依赖注入方式注册路由 handler.RegisterRoutesWithDI(router, c) // 创建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("服务器已关闭") }