Files
backend/internal/wire/infrastructure.go

219 lines
5.6 KiB
Go
Raw Normal View History

package wire
import (
"time"
"carrot_bbs/internal/cache"
"carrot_bbs/internal/config"
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/crypto"
"carrot_bbs/internal/pkg/email"
"carrot_bbs/internal/pkg/hook"
"carrot_bbs/internal/pkg/openai"
"carrot_bbs/internal/pkg/redis"
"carrot_bbs/internal/pkg/s3"
"carrot_bbs/internal/pkg/sse"
"carrot_bbs/internal/repository"
"carrot_bbs/internal/service"
"github.com/google/wire"
"go.uber.org/zap"
"gorm.io/gorm"
)
// InfrastructureSet 基础设施 Provider Set
var InfrastructureSet = wire.NewSet(
// 配置
ProvideConfig,
// 日志
ProvideLogger,
// 数据库
ProvideDB,
// 事务管理器
ProvideTransactionManager,
// Redis 和缓存
ProvideRedisClient,
ProvideCache,
// 钩子系统
ProvideHookManager,
ProvideBuiltinHooks,
ProvideModerationHooks,
// SSE Hub
ProvideSSEHub,
// 外部服务客户端
ProvideOpenAIClient,
ProvideEmailClient,
ProvideS3Client,
// 消息加密器
ProvideMessageEncryptor,
)
// ProvideConfig 加载配置
func ProvideConfig() (*config.Config, error) {
return config.Load("configs/config.yaml")
}
// ProvideDB 提供数据库连接
func ProvideDB(cfg *config.Config) (*gorm.DB, error) {
return model.NewDB(&cfg.Database)
}
// ProvideRedisClient 提供 Redis 客户端
func ProvideRedisClient(cfg *config.Config) *redis.Client {
client, err := redis.New(&cfg.Redis)
if err != nil {
zap.L().Warn("Failed to connect to Redis, falling back to memory cache",
zap.Error(err),
)
return nil
}
return client
}
// ProvideCache 提供缓存实例
func ProvideCache(cfg *config.Config, redisClient *redis.Client) cache.Cache {
cache.Configure(cache.Settings{
Enabled: cfg.Cache.Enabled,
KeyPrefix: cfg.Cache.KeyPrefix,
DefaultTTL: time.Duration(cfg.Cache.DefaultTTL) * time.Second,
NullTTL: time.Duration(cfg.Cache.NullTTL) * time.Second,
JitterRatio: cfg.Cache.JitterRatio,
PostListTTL: time.Duration(cfg.Cache.Modules.PostList) * time.Second,
ConversationTTL: time.Duration(cfg.Cache.Modules.Conversation) * time.Second,
UnreadCountTTL: time.Duration(cfg.Cache.Modules.UnreadCount) * time.Second,
GroupMembersTTL: time.Duration(cfg.Cache.Modules.GroupMembers) * time.Second,
DisableFlushDB: cfg.Cache.DisableFlushDB,
})
if cfg.Cache.Local.Enabled {
layeredCache := cache.NewLayeredCache(redisClient, &cache.LayeredCacheOptions{
LocalSize: cfg.Cache.Local.Size,
LocalBuckets: cfg.Cache.Local.Buckets,
LocalDefaultTTL: time.Duration(cfg.Cache.Local.DefaultTTL) * time.Second,
KeyPrefix: cfg.Cache.KeyPrefix,
Enabled: cfg.Cache.Enabled,
})
zap.L().Info("Initialized layered cache (local LRU + Redis)")
return layeredCache
}
if redisClient == nil {
zap.L().Warn("Redis client is nil, cache will not be available")
return nil
}
cacheInstance := cache.NewRedisCache(redisClient)
zap.L().Info("Initialized Redis cache via dependency injection")
return cacheInstance
}
// ProvideHookManager 提供钩子管理器
func ProvideHookManager() *hook.Manager {
return hook.NewManager(&hook.ManagerOptions{
MaxConcurrentAsync: 100,
Enabled: true,
})
}
// ProvideBuiltinHooks 注册内置钩子
func ProvideBuiltinHooks(manager *hook.Manager) *hook.BuiltinHooks {
builtin := hook.NewBuiltinHooks(manager)
builtin.RegisterAll()
zap.L().Info("Registered builtin hooks")
return builtin
}
// ProvideModerationHooks 注册审核钩子
func ProvideModerationHooks(
manager *hook.Manager,
postAIService *service.PostAIService,
postRepo repository.PostRepository,
commentRepo repository.CommentRepository,
cfg *config.Config,
) *hook.ModerationHooks {
strictMode := cfg.OpenAI.StrictModeration
moderationHooks := hook.NewModerationHooks(
postAIService,
nil,
postRepo,
commentRepo,
strictMode,
"***",
)
moderationHooks.RegisterAll(manager)
zap.L().Info("Registered moderation hooks",
zap.Bool("strict_mode", strictMode),
)
return moderationHooks
}
// ProvideSSEHub 提供 SSE Hub
func ProvideSSEHub() *sse.Hub {
return sse.NewHub()
}
// ProvideOpenAIClient 提供 OpenAI 客户端
func ProvideOpenAIClient(cfg *config.Config) openai.Client {
return openai.NewClient(openai.ConfigFromAppConfig(&cfg.OpenAI))
}
// ProvideEmailClient 提供邮件客户端
func ProvideEmailClient(cfg *config.Config) email.Client {
return email.NewClient(email.ConfigFromAppConfig(&cfg.Email))
}
// ProvideS3Client 提供 S3 客户端
func ProvideS3Client(cfg *config.Config) (*s3.Client, error) {
return s3.New(&cfg.S3)
}
// ProvideTransactionManager 提供事务管理器
func ProvideTransactionManager(db *gorm.DB) repository.TransactionManager {
return repository.NewTransactionManager(db)
}
// ProvideMessageEncryptor 提供消息加密器
func ProvideMessageEncryptor(cfg *config.Config) error {
if !cfg.Encryption.Enabled {
zap.L().Info("Message encryption is disabled")
return nil
}
if len(cfg.Encryption.Key) != 32 {
zap.L().Error("Encryption key must be 32 bytes for AES-256",
zap.Int("actual_length", len(cfg.Encryption.Key)),
)
return nil
}
if err := crypto.InitMessageEncryptor(cfg.Encryption.Key, cfg.Encryption.KeyVersion); err != nil {
zap.L().Error("Failed to initialize message encryptor", zap.Error(err))
return err
}
zap.L().Info("Message encryption initialized successfully",
zap.Int("key_version", cfg.Encryption.KeyVersion),
)
return nil
}
// ProvideLogger 提供 Zap Logger
func ProvideLogger() *zap.Logger {
logger, err := zap.NewProduction()
if err != nil {
panic("Failed to create logger: " + err.Error())
}
// 设置为全局 logger以便在其他地方使用 zap.L()
zap.ReplaceGlobals(logger)
return logger
}