- Removed Gorse-related configurations, handlers, and dependencies from the codebase. - Introduced HotRank feature with configuration options for ranking posts based on recent activity. - Updated application structure to support HotRank processing, including new caching mechanisms and database interactions. - Cleaned up related DTOs and repository methods to reflect the removal of Gorse and the addition of HotRank functionality.
219 lines
5.6 KiB
Go
219 lines
5.6 KiB
Go
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
|
||
}
|