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:
2026-03-13 09:38:18 +08:00
parent 1216423350
commit cf36b1350d
49 changed files with 2571 additions and 2218 deletions

View File

@@ -11,21 +11,24 @@ import (
"carrot_bbs/internal/pkg/gorse"
"carrot_bbs/internal/pkg/response"
gorseio "github.com/gorse-io/gorse-go"
"github.com/gin-gonic/gin"
gorseio "github.com/gorse-io/gorse-go"
"gorm.io/gorm"
)
// GorseHandler Gorse推荐处理器
type GorseHandler struct {
importPassword string
gorseConfig config.GorseConfig
db *gorm.DB
}
// NewGorseHandler 创建Gorse处理器
func NewGorseHandler(cfg config.GorseConfig) *GorseHandler {
func NewGorseHandler(cfg config.GorseConfig, db *gorm.DB) *GorseHandler {
return &GorseHandler{
importPassword: cfg.ImportPassword,
gorseConfig: cfg,
db: db,
}
}
@@ -98,7 +101,7 @@ func (h *GorseHandler) importAllData(ctx context.Context) (gin.H, error) {
// 导入帖子
var posts []model.Post
if err := model.DB.Find(&posts).Error; err != nil {
if err := h.db.Find(&posts).Error; err != nil {
return nil, err
}
for _, post := range posts {
@@ -126,7 +129,7 @@ func (h *GorseHandler) importAllData(ctx context.Context) (gin.H, error) {
// 导入用户
var users []model.User
if err := model.DB.Find(&users).Error; err != nil {
if err := h.db.Find(&users).Error; err != nil {
return nil, err
}
for _, user := range users {
@@ -148,7 +151,7 @@ func (h *GorseHandler) importAllData(ctx context.Context) (gin.H, error) {
// 导入点赞
var likes []model.PostLike
if err := model.DB.Find(&likes).Error; err != nil {
if err := h.db.Find(&likes).Error; err != nil {
return nil, err
}
for _, like := range likes {
@@ -167,7 +170,7 @@ func (h *GorseHandler) importAllData(ctx context.Context) (gin.H, error) {
// 导入收藏
var favorites []model.Favorite
if err := model.DB.Find(&favorites).Error; err != nil {
if err := h.db.Find(&favorites).Error; err != nil {
return nil, err
}
for _, fav := range favorites {
@@ -186,7 +189,7 @@ func (h *GorseHandler) importAllData(ctx context.Context) (gin.H, error) {
// 导入评论(按用户-帖子去重)
var comments []model.Comment
if err := model.DB.Where("status = ?", model.CommentStatusPublished).Find(&comments).Error; err != nil {
if err := h.db.Where("status = ?", model.CommentStatusPublished).Find(&comments).Error; err != nil {
return nil, err
}
seen := make(map[string]struct{})
@@ -231,4 +234,4 @@ func buildPostCategories(post *model.Post) []string {
categories = append(categories, "this_week")
}
return categories
}
}

View File

@@ -15,11 +15,11 @@ import (
// GroupHandler 群组处理器
type GroupHandler struct {
groupService service.GroupService
userService *service.UserService
userService service.UserService
}
// NewGroupHandler 创建群组处理器
func NewGroupHandler(groupService service.GroupService, userService *service.UserService) *GroupHandler {
func NewGroupHandler(groupService service.GroupService, userService service.UserService) *GroupHandler {
return &GroupHandler{
groupService: groupService,
userService: userService,

View File

@@ -20,13 +20,13 @@ import (
type MessageHandler struct {
chatService service.ChatService
messageService *service.MessageService
userService *service.UserService
userService service.UserService
groupService service.GroupService
sseHub *sse.Hub
}
// NewMessageHandler 创建消息处理器
func NewMessageHandler(chatService service.ChatService, messageService *service.MessageService, userService *service.UserService, groupService service.GroupService, sseHub *sse.Hub) *MessageHandler {
func NewMessageHandler(chatService service.ChatService, messageService *service.MessageService, userService service.UserService, groupService service.GroupService, sseHub *sse.Hub) *MessageHandler {
return &MessageHandler{
chatService: chatService,
messageService: messageService,

View File

@@ -15,12 +15,12 @@ import (
// PostHandler 帖子处理器
type PostHandler struct {
postService *service.PostService
userService *service.UserService
postService service.PostService
userService service.UserService
}
// NewPostHandler 创建帖子处理器
func NewPostHandler(postService *service.PostService, userService *service.UserService) *PostHandler {
func NewPostHandler(postService service.PostService, userService service.UserService) *PostHandler {
return &PostHandler{
postService: postService,
userService: userService,

View File

@@ -4,6 +4,7 @@ import (
"strconv"
"carrot_bbs/internal/cache"
"github.com/gin-gonic/gin"
"carrot_bbs/internal/dto"
@@ -16,16 +17,19 @@ import (
type SystemMessageHandler struct {
systemMsgService service.SystemMessageService
notifyRepo *repository.SystemNotificationRepository
cache cache.Cache
}
// NewSystemMessageHandler 创建系统消息处理器
func NewSystemMessageHandler(
systemMsgService service.SystemMessageService,
notifyRepo *repository.SystemNotificationRepository,
cacheBackend cache.Cache,
) *SystemMessageHandler {
return &SystemMessageHandler{
systemMsgService: systemMsgService,
notifyRepo: notifyRepo,
cache: cacheBackend,
}
}
@@ -101,7 +105,7 @@ func (h *SystemMessageHandler) MarkAsRead(c *gin.Context) {
response.InternalServerError(c, "failed to mark as read")
return
}
cache.InvalidateUnreadSystem(cache.GetCache(), userID)
cache.InvalidateUnreadSystem(h.cache, userID)
response.SuccessWithMessage(c, "marked as read", nil)
}
@@ -121,7 +125,7 @@ func (h *SystemMessageHandler) MarkAllAsRead(c *gin.Context) {
response.InternalServerError(c, "failed to mark all as read")
return
}
cache.InvalidateUnreadSystem(cache.GetCache(), userID)
cache.InvalidateUnreadSystem(h.cache, userID)
response.SuccessWithMessage(c, "all messages marked as read", nil)
}
@@ -148,7 +152,7 @@ func (h *SystemMessageHandler) DeleteSystemMessage(c *gin.Context) {
response.InternalServerError(c, "failed to delete notification")
return
}
cache.InvalidateUnreadSystem(cache.GetCache(), userID)
cache.InvalidateUnreadSystem(h.cache, userID)
response.SuccessWithMessage(c, "notification deleted", nil)
}

View File

@@ -12,12 +12,12 @@ import (
// UserHandler 用户处理器
type UserHandler struct {
userService *service.UserService
userService service.UserService
jwtService *service.JWTService
}
// NewUserHandler 创建用户处理器
func NewUserHandler(userService *service.UserService) *UserHandler {
func NewUserHandler(userService service.UserService) *UserHandler {
return &UserHandler{
userService: userService,
}

View File

@@ -14,11 +14,11 @@ import (
// VoteHandler 投票处理器
type VoteHandler struct {
voteService *service.VoteService
postService *service.PostService
postService service.PostService
}
// NewVoteHandler 创建投票处理器
func NewVoteHandler(voteService *service.VoteService, postService *service.PostService) *VoteHandler {
func NewVoteHandler(voteService *service.VoteService, postService service.PostService) *VoteHandler {
return &VoteHandler{
voteService: voteService,
postService: postService,