refactor: introduce Wire dependency injection and interface-based architecture
- Add Google Wire for compile-time dependency injection - Replace concrete service types with interfaces across handlers - Remove global state (DB, cache) in favor of constructor injection - Split monolithic files into focused modules: - config: separate files for each config domain - dto: converters split by domain (user, post, message, group) - cache: separate metrics.go and redis_cache.go - Introduce unified apperrors package with string-based error codes - Add transaction support with context-aware repository methods - Upgrade golang.org/x/crypto from 0.17.0 to 0.26.0
This commit is contained in:
74
internal/wire/handler.go
Normal file
74
internal/wire/handler.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"carrot_bbs/internal/cache"
|
||||
"carrot_bbs/internal/config"
|
||||
"carrot_bbs/internal/handler"
|
||||
"carrot_bbs/internal/pkg/sse"
|
||||
"carrot_bbs/internal/repository"
|
||||
"carrot_bbs/internal/service"
|
||||
|
||||
"github.com/google/wire"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// HandlerSet Handler 层 Provider Set
|
||||
var HandlerSet = wire.NewSet(
|
||||
// 直接使用构造函数的 Handler
|
||||
handler.NewUserHandler,
|
||||
handler.NewCommentHandler,
|
||||
handler.NewNotificationHandler,
|
||||
handler.NewUploadHandler,
|
||||
handler.NewPushHandler,
|
||||
handler.NewStickerHandler,
|
||||
handler.NewVoteHandler,
|
||||
handler.NewScheduleHandler,
|
||||
|
||||
// 需要特殊处理的 Handler
|
||||
ProvidePostHandler,
|
||||
ProvideMessageHandler,
|
||||
ProvideSystemMessageHandler,
|
||||
ProvideGroupHandler,
|
||||
ProvideGorseHandler,
|
||||
)
|
||||
|
||||
// ProvidePostHandler 提供帖子处理器
|
||||
func ProvidePostHandler(
|
||||
postService service.PostService,
|
||||
userService service.UserService,
|
||||
) *handler.PostHandler {
|
||||
return handler.NewPostHandler(postService, userService)
|
||||
}
|
||||
|
||||
// ProvideMessageHandler 提供消息处理器
|
||||
func ProvideMessageHandler(
|
||||
chatService service.ChatService,
|
||||
messageService *service.MessageService,
|
||||
userService service.UserService,
|
||||
groupService service.GroupService,
|
||||
sseHub *sse.Hub,
|
||||
) *handler.MessageHandler {
|
||||
return handler.NewMessageHandler(chatService, messageService, userService, groupService, sseHub)
|
||||
}
|
||||
|
||||
// ProvideSystemMessageHandler 提供系统消息处理器
|
||||
func ProvideSystemMessageHandler(
|
||||
systemMsgService service.SystemMessageService,
|
||||
systemNotificationRepo *repository.SystemNotificationRepository,
|
||||
cacheBackend cache.Cache,
|
||||
) *handler.SystemMessageHandler {
|
||||
return handler.NewSystemMessageHandler(systemMsgService, systemNotificationRepo, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideGroupHandler 提供群组处理器
|
||||
func ProvideGroupHandler(
|
||||
groupService service.GroupService,
|
||||
userService service.UserService,
|
||||
) *handler.GroupHandler {
|
||||
return handler.NewGroupHandler(groupService, userService)
|
||||
}
|
||||
|
||||
// ProvideGorseHandler 提供 Gorse 处理器
|
||||
func ProvideGorseHandler(cfg *config.Config, db *gorm.DB) *handler.GorseHandler {
|
||||
return handler.NewGorseHandler(cfg.Gorse, db)
|
||||
}
|
||||
121
internal/wire/infrastructure.go
Normal file
121
internal/wire/infrastructure.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"carrot_bbs/internal/cache"
|
||||
"carrot_bbs/internal/config"
|
||||
"carrot_bbs/internal/model"
|
||||
"carrot_bbs/internal/pkg/email"
|
||||
"carrot_bbs/internal/pkg/gorse"
|
||||
"carrot_bbs/internal/pkg/openai"
|
||||
"carrot_bbs/internal/pkg/redis"
|
||||
"carrot_bbs/internal/pkg/s3"
|
||||
"carrot_bbs/internal/pkg/sse"
|
||||
"carrot_bbs/internal/repository"
|
||||
|
||||
"github.com/google/wire"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// InfrastructureSet 基础设施 Provider Set
|
||||
var InfrastructureSet = wire.NewSet(
|
||||
// 配置
|
||||
ProvideConfig,
|
||||
|
||||
// 数据库
|
||||
ProvideDB,
|
||||
|
||||
// 事务管理器
|
||||
ProvideTransactionManager,
|
||||
|
||||
// Redis 和缓存
|
||||
ProvideRedisClient,
|
||||
ProvideCache,
|
||||
|
||||
// SSE Hub
|
||||
ProvideSSEHub,
|
||||
|
||||
// 外部服务客户端
|
||||
ProvideGorseClient,
|
||||
ProvideOpenAIClient,
|
||||
ProvideEmailClient,
|
||||
ProvideS3Client,
|
||||
)
|
||||
|
||||
// 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 {
|
||||
log.Printf("[WARNING] Failed to connect to Redis: %v, falling back to memory cache", 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,
|
||||
})
|
||||
|
||||
// 直接创建 RedisCache 实例,不依赖全局变量
|
||||
if redisClient == nil {
|
||||
log.Println("[Wire] Warning: Redis client is nil, cache will not be available")
|
||||
return nil
|
||||
}
|
||||
|
||||
cacheInstance := cache.NewRedisCache(redisClient)
|
||||
log.Println("[Wire] Initialized Redis cache via dependency injection")
|
||||
return cacheInstance
|
||||
}
|
||||
|
||||
// ProvideSSEHub 提供 SSE Hub
|
||||
func ProvideSSEHub() *sse.Hub {
|
||||
return sse.NewHub()
|
||||
}
|
||||
|
||||
// ProvideGorseClient 提供 Gorse 客户端
|
||||
func ProvideGorseClient(cfg *config.Config) gorse.Client {
|
||||
return gorse.NewClient(gorse.ConfigFromAppConfig(&cfg.Gorse))
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
11
internal/wire/provider_set.go
Normal file
11
internal/wire/provider_set.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package wire
|
||||
|
||||
import "github.com/google/wire"
|
||||
|
||||
// AllSet 包含所有 Provider Set
|
||||
var AllSet = wire.NewSet(
|
||||
InfrastructureSet,
|
||||
RepositorySet,
|
||||
ServiceSet,
|
||||
HandlerSet,
|
||||
)
|
||||
29
internal/wire/repository.go
Normal file
29
internal/wire/repository.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"carrot_bbs/internal/repository"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// RepositorySet Repository 层 Provider Set
|
||||
var RepositorySet = wire.NewSet(
|
||||
repository.NewUserRepository,
|
||||
repository.NewPostRepository,
|
||||
repository.NewCommentRepository,
|
||||
repository.NewMessageRepository,
|
||||
repository.NewNotificationRepository,
|
||||
repository.NewPushRecordRepository,
|
||||
repository.NewDeviceTokenRepository,
|
||||
repository.NewSystemNotificationRepository,
|
||||
repository.NewGroupRepository,
|
||||
repository.NewStickerRepository,
|
||||
repository.NewVoteRepository,
|
||||
repository.NewScheduleRepository,
|
||||
)
|
||||
|
||||
// Note: 以下 Repository 返回接口类型而非指针,需要单独处理
|
||||
// - ScheduleRepository (repository.ScheduleRepository)
|
||||
// - StickerRepository (repository.StickerRepository)
|
||||
// - GroupRepository (repository.GroupRepository)
|
||||
// 这些已经在各自的 New* 函数中正确返回接口类型,Wire 可以自动处理
|
||||
189
internal/wire/service.go
Normal file
189
internal/wire/service.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"carrot_bbs/internal/cache"
|
||||
"carrot_bbs/internal/config"
|
||||
"carrot_bbs/internal/pkg/email"
|
||||
"carrot_bbs/internal/pkg/gorse"
|
||||
"carrot_bbs/internal/pkg/openai"
|
||||
"carrot_bbs/internal/pkg/s3"
|
||||
"carrot_bbs/internal/pkg/sse"
|
||||
"carrot_bbs/internal/repository"
|
||||
"carrot_bbs/internal/service"
|
||||
|
||||
"github.com/google/wire"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ServiceSet Service 层 Provider Set
|
||||
var ServiceSet = wire.NewSet(
|
||||
// JWT 服务(需要配置参数)
|
||||
ProvideJWTService,
|
||||
|
||||
// 基础服务
|
||||
ProvideEmailService,
|
||||
ProvidePostAIService,
|
||||
|
||||
// 核心服务(按依赖顺序)
|
||||
ProvidePushService,
|
||||
ProvideSystemMessageService,
|
||||
ProvidePostService,
|
||||
ProvideCommentService,
|
||||
ProvideMessageService,
|
||||
ProvideNotificationService,
|
||||
ProvideUserService,
|
||||
ProvideStickerService,
|
||||
ProvideVoteService,
|
||||
ProvideChatService,
|
||||
ProvideScheduleService,
|
||||
ProvideGroupService,
|
||||
ProvideUploadService,
|
||||
)
|
||||
|
||||
// ProvideJWTService 提供 JWT 服务
|
||||
func ProvideJWTService(cfg *config.Config) *service.JWTService {
|
||||
return service.NewJWTService(
|
||||
cfg.JWT.Secret,
|
||||
int64(cfg.JWT.AccessTokenExpire.Seconds()),
|
||||
int64(cfg.JWT.RefreshTokenExpire.Seconds()),
|
||||
)
|
||||
}
|
||||
|
||||
// ProvideEmailService 提供邮件服务
|
||||
func ProvideEmailService(client email.Client) service.EmailService {
|
||||
return service.NewEmailService(client)
|
||||
}
|
||||
|
||||
// ProvidePostAIService 提供 AI 服务
|
||||
func ProvidePostAIService(client openai.Client) *service.PostAIService {
|
||||
return service.NewPostAIService(client)
|
||||
}
|
||||
|
||||
// ProvidePushService 提供推送服务
|
||||
func ProvidePushService(
|
||||
pushRepo *repository.PushRecordRepository,
|
||||
deviceTokenRepo *repository.DeviceTokenRepository,
|
||||
messageRepo *repository.MessageRepository,
|
||||
sseHub *sse.Hub,
|
||||
) service.PushService {
|
||||
return service.NewPushService(pushRepo, deviceTokenRepo, messageRepo, sseHub)
|
||||
}
|
||||
|
||||
// ProvideSystemMessageService 提供系统消息服务
|
||||
func ProvideSystemMessageService(
|
||||
notifyRepo *repository.SystemNotificationRepository,
|
||||
pushService service.PushService,
|
||||
userRepo *repository.UserRepository,
|
||||
postRepo *repository.PostRepository,
|
||||
cacheBackend cache.Cache,
|
||||
) service.SystemMessageService {
|
||||
return service.NewSystemMessageService(notifyRepo, pushService, userRepo, postRepo, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvidePostService 提供帖子服务
|
||||
func ProvidePostService(
|
||||
postRepo *repository.PostRepository,
|
||||
systemMessageService service.SystemMessageService,
|
||||
gorseClient gorse.Client,
|
||||
postAIService *service.PostAIService,
|
||||
cacheBackend cache.Cache,
|
||||
txManager repository.TransactionManager,
|
||||
) service.PostService {
|
||||
return service.NewPostService(postRepo, systemMessageService, gorseClient, postAIService, cacheBackend, txManager)
|
||||
}
|
||||
|
||||
// ProvideCommentService 提供评论服务
|
||||
func ProvideCommentService(
|
||||
commentRepo *repository.CommentRepository,
|
||||
postRepo *repository.PostRepository,
|
||||
systemMessageService service.SystemMessageService,
|
||||
gorseClient gorse.Client,
|
||||
postAIService *service.PostAIService,
|
||||
cacheBackend cache.Cache,
|
||||
) *service.CommentService {
|
||||
return service.NewCommentService(commentRepo, postRepo, systemMessageService, gorseClient, postAIService, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideMessageService 提供消息服务
|
||||
func ProvideMessageService(
|
||||
db *gorm.DB,
|
||||
messageRepo *repository.MessageRepository,
|
||||
cacheBackend cache.Cache,
|
||||
) *service.MessageService {
|
||||
return service.NewMessageService(db, messageRepo, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideNotificationService 提供通知服务
|
||||
func ProvideNotificationService(
|
||||
notificationRepo *repository.NotificationRepository,
|
||||
cacheBackend cache.Cache,
|
||||
) *service.NotificationService {
|
||||
return service.NewNotificationService(notificationRepo, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideUserService 提供用户服务
|
||||
func ProvideUserService(
|
||||
userRepo *repository.UserRepository,
|
||||
systemMessageService service.SystemMessageService,
|
||||
emailService service.EmailService,
|
||||
cacheBackend cache.Cache,
|
||||
) service.UserService {
|
||||
return service.NewUserService(userRepo, systemMessageService, emailService, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideStickerService 提供表情服务
|
||||
func ProvideStickerService(
|
||||
stickerRepo repository.StickerRepository,
|
||||
) service.StickerService {
|
||||
return service.NewStickerService(stickerRepo)
|
||||
}
|
||||
|
||||
// ProvideVoteService 提供投票服务
|
||||
func ProvideVoteService(
|
||||
voteRepo *repository.VoteRepository,
|
||||
postRepo *repository.PostRepository,
|
||||
cache cache.Cache,
|
||||
postAIService *service.PostAIService,
|
||||
systemMessageService service.SystemMessageService,
|
||||
) *service.VoteService {
|
||||
return service.NewVoteService(voteRepo, postRepo, cache, postAIService, systemMessageService)
|
||||
}
|
||||
|
||||
// ProvideChatService 提供聊天服务
|
||||
// Note: sensitiveService 传 nil,与 main.go 保持一致
|
||||
func ProvideChatService(
|
||||
db *gorm.DB,
|
||||
messageRepo *repository.MessageRepository,
|
||||
userRepo *repository.UserRepository,
|
||||
sseHub *sse.Hub,
|
||||
cacheBackend cache.Cache,
|
||||
) service.ChatService {
|
||||
return service.NewChatService(db, messageRepo, userRepo, nil, sseHub, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideScheduleService 提供日程服务
|
||||
func ProvideScheduleService(
|
||||
scheduleRepo repository.ScheduleRepository,
|
||||
) service.ScheduleService {
|
||||
return service.NewScheduleService(scheduleRepo)
|
||||
}
|
||||
|
||||
// ProvideGroupService 提供群组服务
|
||||
func ProvideGroupService(
|
||||
db *gorm.DB,
|
||||
groupRepo repository.GroupRepository,
|
||||
userRepo *repository.UserRepository,
|
||||
messageRepo *repository.MessageRepository,
|
||||
sseHub *sse.Hub,
|
||||
cacheBackend cache.Cache,
|
||||
) service.GroupService {
|
||||
return service.NewGroupService(db, groupRepo, userRepo, messageRepo, sseHub, cacheBackend)
|
||||
}
|
||||
|
||||
// ProvideUploadService 提供上传服务
|
||||
func ProvideUploadService(
|
||||
s3Client *s3.Client,
|
||||
userService service.UserService,
|
||||
) *service.UploadService {
|
||||
return service.NewUploadService(s3Client, userService)
|
||||
}
|
||||
Reference in New Issue
Block a user