package container import ( "context" "time" "carrotskin/internal/repository" "carrotskin/internal/service" "carrotskin/pkg/auth" "carrotskin/pkg/config" "carrotskin/pkg/database" "carrotskin/pkg/email" "carrotskin/pkg/redis" "carrotskin/pkg/storage" "go.uber.org/zap" "gorm.io/gorm" ) // Container 依赖注入容器 // 集中管理所有依赖,便于测试和维护 type Container struct { // 配置 Config *config.Config // 基础设施依赖 DB *gorm.DB Redis *redis.Client Logger *zap.Logger JWT *auth.JWTService Casbin *auth.CasbinService Storage *storage.StorageClient CacheManager *database.CacheManager // Repository层 UserRepo repository.UserRepository ProfileRepo repository.ProfileRepository TextureRepo repository.TextureRepository ClientRepo repository.ClientRepository YggdrasilRepo repository.YggdrasilRepository // Service层 UserService service.UserService ProfileService service.ProfileService TextureService service.TextureService TokenService service.TokenService YggdrasilService service.YggdrasilService VerificationService service.VerificationService CaptchaService service.CaptchaService SignatureService *service.SignatureService } // NewContainer 创建依赖容器 func NewContainer( cfg *config.Config, db *gorm.DB, redisClient *redis.Client, logger *zap.Logger, jwtService *auth.JWTService, casbinService *auth.CasbinService, storageClient *storage.StorageClient, emailService *email.Service, ) *Container { // 创建缓存管理器 cacheManager := database.NewCacheManager(redisClient, database.CacheConfig{ Prefix: "carrotskin:", Expiration: 5 * time.Minute, Enabled: true, Policy: database.CachePolicy{ UserTTL: 5 * time.Minute, UserEmailTTL: 5 * time.Minute, ProfileTTL: 5 * time.Minute, ProfileListTTL: 3 * time.Minute, TextureTTL: 5 * time.Minute, TextureListTTL: 2 * time.Minute, }, }) c := &Container{ Config: cfg, DB: db, Redis: redisClient, Logger: logger, JWT: jwtService, Casbin: casbinService, Storage: storageClient, CacheManager: cacheManager, } // 初始化Repository c.UserRepo = repository.NewUserRepository(db) c.ProfileRepo = repository.NewProfileRepository(db) c.TextureRepo = repository.NewTextureRepository(db) c.ClientRepo = repository.NewClientRepository(db) c.YggdrasilRepo = repository.NewYggdrasilRepository(db) // 初始化SignatureService(作为依赖注入,避免在容器中创建并立即调用) // 将SignatureService添加到容器中,供其他服务使用 c.SignatureService = service.NewSignatureService(c.ProfileRepo, redisClient, logger) // 初始化Service(注入缓存管理器) c.UserService = service.NewUserService(cfg, c.UserRepo, jwtService, redisClient, cacheManager, storageClient, logger) c.ProfileService = service.NewProfileService(c.ProfileRepo, c.UserRepo, cacheManager, logger) c.TextureService = service.NewTextureService(c.TextureRepo, c.UserRepo, storageClient, cacheManager, logger, db) // 获取Yggdrasil私钥并创建JWT服务(TokenService需要) // 注意:这里仍然需要预先初始化,因为TokenService在创建时需要YggdrasilJWT // 但SignatureService已经作为依赖注入,降低了耦合度 // 使用后台 ctx(启动阶段不依赖请求 ctx) initCtx, cancelInit := context.WithTimeout(context.Background(), 30*time.Second) _, privateKey, err := c.SignatureService.GetOrCreateYggdrasilKeyPair(initCtx) cancelInit() if err != nil { logger.Fatal("获取Yggdrasil私钥失败", zap.Error(err)) } yggdrasilJWT := auth.NewYggdrasilJWTService(privateKey, "carrotskin") // 创建Redis Token存储(必须使用Redis,包括miniredis回退) if redisClient == nil { logger.Fatal("Redis客户端未初始化,无法创建Token服务") } tokenStore := auth.NewTokenStoreRedis( redisClient, logger, auth.WithKeyPrefix("token:"), auth.WithDefaultTTL(24*time.Hour), auth.WithStaleTTL(30*24*time.Hour), auth.WithMaxTokensPerUser(10), ) c.TokenService = service.NewTokenServiceRedis(tokenStore, c.ClientRepo, c.ProfileRepo, yggdrasilJWT, logger) // 使用组合服务(内部包含认证、会话、序列化、证书服务) c.YggdrasilService = service.NewYggdrasilServiceComposite(c.UserRepo, c.ProfileRepo, c.YggdrasilRepo, c.TextureRepo, c.SignatureService, redisClient, logger, c.TokenService) // 初始化其他服务 c.CaptchaService = service.NewCaptchaService(cfg, redisClient, logger) // 初始化VerificationService(需要email.Service) if emailService != nil { c.VerificationService = service.NewVerificationService(cfg, redisClient, emailService) } return c }