2026-04-22 16:01:59 +08:00
|
|
|
|
package wire
|
2026-03-13 09:38:18 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
2026-04-22 16:01:59 +08:00
|
|
|
|
"with_you/internal/cache"
|
|
|
|
|
|
"with_you/internal/config"
|
|
|
|
|
|
"with_you/internal/model"
|
|
|
|
|
|
"with_you/internal/pkg/crypto"
|
|
|
|
|
|
"with_you/internal/pkg/email"
|
|
|
|
|
|
"with_you/internal/pkg/hook"
|
|
|
|
|
|
"with_you/internal/pkg/openai"
|
|
|
|
|
|
"with_you/internal/pkg/redis"
|
|
|
|
|
|
"with_you/internal/pkg/s3"
|
|
|
|
|
|
"with_you/internal/pkg/tencent"
|
|
|
|
|
|
"with_you/internal/pkg/ws"
|
|
|
|
|
|
"with_you/internal/repository"
|
|
|
|
|
|
"with_you/internal/service"
|
2026-03-13 09:38:18 +08:00
|
|
|
|
|
|
|
|
|
|
"github.com/google/wire"
|
2026-03-13 20:40:20 +08:00
|
|
|
|
"go.uber.org/zap"
|
2026-03-13 09:38:18 +08:00
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// InfrastructureSet 基础设施 Provider Set
|
|
|
|
|
|
var InfrastructureSet = wire.NewSet(
|
|
|
|
|
|
// 配置
|
|
|
|
|
|
ProvideConfig,
|
|
|
|
|
|
|
2026-03-13 20:40:20 +08:00
|
|
|
|
// 日志
|
|
|
|
|
|
ProvideLogger,
|
|
|
|
|
|
|
2026-03-13 09:38:18 +08:00
|
|
|
|
// 数据库
|
|
|
|
|
|
ProvideDB,
|
|
|
|
|
|
|
|
|
|
|
|
// 事务管理器
|
|
|
|
|
|
ProvideTransactionManager,
|
|
|
|
|
|
|
|
|
|
|
|
// Redis 和缓存
|
|
|
|
|
|
ProvideRedisClient,
|
|
|
|
|
|
ProvideCache,
|
|
|
|
|
|
|
2026-03-20 12:23:28 +08:00
|
|
|
|
// 钩子系统
|
|
|
|
|
|
ProvideHookManager,
|
|
|
|
|
|
ProvideBuiltinHooks,
|
|
|
|
|
|
ProvideModerationHooks,
|
|
|
|
|
|
|
2026-03-26 21:17:49 +08:00
|
|
|
|
// WebSocket Hub
|
|
|
|
|
|
ProvideWSHub,
|
2026-03-13 09:38:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 外部服务客户端
|
|
|
|
|
|
ProvideOpenAIClient,
|
2026-04-21 22:31:30 +08:00
|
|
|
|
ProvideTencentClient,
|
2026-03-13 09:38:18 +08:00
|
|
|
|
ProvideEmailClient,
|
|
|
|
|
|
ProvideS3Client,
|
2026-03-17 10:10:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 消息加密器
|
|
|
|
|
|
ProvideMessageEncryptor,
|
2026-03-13 09:38:18 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 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 {
|
2026-03-17 00:47:17 +08:00
|
|
|
|
zap.L().Warn("Failed to connect to Redis, falling back to memory cache",
|
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
|
)
|
2026-03-13 09:38:18 +08:00
|
|
|
|
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,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-03-20 12:23:28 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-13 09:38:18 +08:00
|
|
|
|
if redisClient == nil {
|
2026-03-17 00:47:17 +08:00
|
|
|
|
zap.L().Warn("Redis client is nil, cache will not be available")
|
2026-03-13 09:38:18 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cacheInstance := cache.NewRedisCache(redisClient)
|
2026-03-17 00:47:17 +08:00
|
|
|
|
zap.L().Info("Initialized Redis cache via dependency injection")
|
2026-03-13 09:38:18 +08:00
|
|
|
|
return cacheInstance
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-20 12:23:28 +08:00
|
|
|
|
// 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,
|
2026-03-26 18:14:16 +08:00
|
|
|
|
postRepo repository.PostRepository,
|
|
|
|
|
|
commentRepo repository.CommentRepository,
|
2026-04-15 11:50:47 +08:00
|
|
|
|
userRepo repository.UserRepository,
|
|
|
|
|
|
sensitiveService service.SensitiveService,
|
2026-03-20 12:23:28 +08:00
|
|
|
|
cfg *config.Config,
|
|
|
|
|
|
) *hook.ModerationHooks {
|
|
|
|
|
|
strictMode := cfg.OpenAI.StrictModeration
|
|
|
|
|
|
|
|
|
|
|
|
moderationHooks := hook.NewModerationHooks(
|
|
|
|
|
|
postAIService,
|
2026-04-15 11:50:47 +08:00
|
|
|
|
sensitiveService,
|
2026-03-20 12:23:28 +08:00
|
|
|
|
postRepo,
|
|
|
|
|
|
commentRepo,
|
2026-04-15 11:50:47 +08:00
|
|
|
|
userRepo,
|
2026-03-20 12:23:28 +08:00
|
|
|
|
strictMode,
|
|
|
|
|
|
"***",
|
|
|
|
|
|
)
|
|
|
|
|
|
moderationHooks.RegisterAll(manager)
|
|
|
|
|
|
zap.L().Info("Registered moderation hooks",
|
|
|
|
|
|
zap.Bool("strict_mode", strictMode),
|
|
|
|
|
|
)
|
|
|
|
|
|
return moderationHooks
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-26 21:17:49 +08:00
|
|
|
|
// ProvideWSHub 提供 WebSocket Hub
|
|
|
|
|
|
func ProvideWSHub() *ws.Hub {
|
|
|
|
|
|
return ws.NewHub()
|
2026-03-13 09:38:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProvideOpenAIClient 提供 OpenAI 客户端
|
|
|
|
|
|
func ProvideOpenAIClient(cfg *config.Config) openai.Client {
|
|
|
|
|
|
return openai.NewClient(openai.ConfigFromAppConfig(&cfg.OpenAI))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-21 22:31:30 +08:00
|
|
|
|
// ProvideTencentClient 提供腾讯云TMS客户端
|
|
|
|
|
|
func ProvideTencentClient(cfg *config.Config) tencent.Client {
|
|
|
|
|
|
return tencent.NewClient(tencent.Config{
|
|
|
|
|
|
Enabled: cfg.TencentTMS.Enabled,
|
|
|
|
|
|
SecretID: cfg.TencentTMS.SecretID,
|
|
|
|
|
|
SecretKey: cfg.TencentTMS.SecretKey,
|
|
|
|
|
|
Region: cfg.TencentTMS.Region,
|
|
|
|
|
|
BizType: cfg.TencentTMS.BizType,
|
|
|
|
|
|
Timeout: cfg.TencentTMS.Timeout,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-13 09:38:18 +08:00
|
|
|
|
// 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)
|
|
|
|
|
|
}
|
2026-03-13 20:40:20 +08:00
|
|
|
|
|
2026-03-17 10:10:49 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-13 20:40:20 +08:00
|
|
|
|
// ProvideLogger 提供 Zap Logger
|
|
|
|
|
|
func ProvideLogger() *zap.Logger {
|
|
|
|
|
|
logger, err := zap.NewProduction()
|
|
|
|
|
|
if err != nil {
|
2026-03-17 00:47:17 +08:00
|
|
|
|
panic("Failed to create logger: " + err.Error())
|
2026-03-13 20:40:20 +08:00
|
|
|
|
}
|
2026-03-17 00:47:17 +08:00
|
|
|
|
// 设置为全局 logger,以便在其他地方使用 zap.L()
|
|
|
|
|
|
zap.ReplaceGlobals(logger)
|
2026-03-13 20:40:20 +08:00
|
|
|
|
return logger
|
|
|
|
|
|
}
|