From 736344f1230c05abe3c64d3825eb120a9b9dbe66 Mon Sep 17 00:00:00 2001 From: lafay <2021211506@stu.hit.edu.cn> Date: Sat, 28 Mar 2026 07:03:21 +0800 Subject: [PATCH] refactor(di): migrate from setter to constructor injection for logService - Remove SetLogService methods from user, post, comment, and admin post services - Add logService as constructor parameter to all dependent services - Centralize call-related and message error definitions in app_errors.go - Add ConversationID field to WSEventResponse for improved message tracking - Simplify wire provider functions by removing manual setter calls --- cmd/server/wire_gen.go | 34 ++--- go.sum | 2 + internal/dto/dto.go | 171 +++++++++++++------------ internal/errors/app_errors.go | 28 ++++ internal/handler/message_handler.go | 15 ++- internal/handler/user_handler.go | 8 +- internal/handler/ws_handler.go | 20 +-- internal/service/admin_post_service.go | 12 +- internal/service/call_service.go | 50 +++----- internal/service/comment_service.go | 9 +- internal/service/post_service.go | 13 +- internal/service/push_service.go | 19 +-- internal/service/user_service.go | 11 +- internal/wire/handler.go | 52 +------- internal/wire/service.go | 13 +- 15 files changed, 203 insertions(+), 254 deletions(-) diff --git a/cmd/server/wire_gen.go b/cmd/server/wire_gen.go index 0f8fc7c..b7407cf 100644 --- a/cmd/server/wire_gen.go +++ b/cmd/server/wire_gen.go @@ -39,18 +39,6 @@ func InitializeApp() (*App, error) { systemMessageService := wire.ProvideSystemMessageService(systemNotificationRepository, pushService, userRepository, postRepository, cache) emailClient := wire.ProvideEmailClient(config) emailService := wire.ProvideEmailService(emailClient) - userService := wire.ProvideUserService(userRepository, systemMessageService, emailService, cache) - userActivityRepository := wire.ProvideUserActivityRepository(db, cache) - userActivityService := wire.ProvideUserActivityService(userActivityRepository) - openaiClient := wire.ProvideOpenAIClient(config) - postAIService := wire.ProvidePostAIService(openaiClient) - transactionManager := wire.ProvideTransactionManager(db) - manager := wire.ProvideHookManager() - commentRepository := repository.NewCommentRepository(db) - moderationHooks := wire.ProvideModerationHooks(manager, postAIService, postRepository, commentRepository, config) - builtinHooks := wire.ProvideBuiltinHooks(manager) - postService := wire.ProvidePostService(postRepository, systemMessageService, postAIService, cache, transactionManager, manager, moderationHooks, builtinHooks) - commentService := wire.ProvideCommentService(commentRepository, postRepository, systemMessageService, postAIService, cache, manager) operationLogRepository := repository.NewOperationLogRepository(db) loginLogRepository := repository.NewLoginLogRepository(db) dataChangeLogRepository := repository.NewDataChangeLogRepository(db) @@ -60,10 +48,22 @@ func InitializeApp() (*App, error) { loginLogService := wire.ProvideLoginLogService(asyncLogManager, loginLogRepository) dataChangeLogService := wire.ProvideDataChangeLogService(asyncLogManager, dataChangeLogRepository) logService := wire.ProvideLogService(operationLogService, loginLogService, dataChangeLogService) - userHandler := wire.ProvideUserHandler(userService, userActivityService, postService, commentService, logService) + userService := wire.ProvideUserService(userRepository, systemMessageService, emailService, cache, logService) + userActivityRepository := wire.ProvideUserActivityRepository(db, cache) + userActivityService := wire.ProvideUserActivityService(userActivityRepository) + userHandler := handler.NewUserHandler(userService, userActivityService, logService) + openaiClient := wire.ProvideOpenAIClient(config) + postAIService := wire.ProvidePostAIService(openaiClient) + transactionManager := wire.ProvideTransactionManager(db) + manager := wire.ProvideHookManager() + commentRepository := repository.NewCommentRepository(db) + moderationHooks := wire.ProvideModerationHooks(manager, postAIService, postRepository, commentRepository, config) + builtinHooks := wire.ProvideBuiltinHooks(manager) + postService := wire.ProvidePostService(postRepository, systemMessageService, postAIService, cache, transactionManager, manager, moderationHooks, builtinHooks, logService) channelRepository := repository.NewChannelRepository(db) channelService := wire.ProvideChannelService(channelRepository, cache) - postHandler := wire.ProvidePostHandler(postService, userService, channelService, logService) + postHandler := handler.NewPostHandler(postService, userService, channelService) + commentService := wire.ProvideCommentService(commentRepository, postRepository, systemMessageService, postAIService, cache, manager, logService) commentHandler := handler.NewCommentHandler(commentService) s3Client, err := wire.ProvideS3Client(config) if err != nil { @@ -104,7 +104,7 @@ func InitializeApp() (*App, error) { roleHandler := handler.NewRoleHandler(roleService) adminUserService := wire.ProvideAdminUserService(userRepository) adminUserHandler := handler.NewAdminUserHandler(adminUserService) - adminPostService := wire.ProvideAdminPostService(postRepository, cache) + adminPostService := wire.ProvideAdminPostService(postRepository, cache, logService) adminPostHandler := handler.NewAdminPostHandler(adminPostService) adminCommentService := wire.ProvideAdminCommentService(commentRepository, postRepository) adminCommentHandler := handler.NewAdminCommentHandler(adminCommentService) @@ -117,10 +117,10 @@ func InitializeApp() (*App, error) { qrCodeHandler := handler.NewQRCodeHandler(qrCodeLoginService) materialSubjectRepository := repository.NewMaterialSubjectRepository(db) materialFileRepository := repository.NewMaterialFileRepository(db) - callRepository := repository.NewCallRepository(db) materialService := wire.ProvideMaterialService(materialSubjectRepository, materialFileRepository) - callService := wire.ProvideCallService(callRepository, hub, config, db) materialHandler := handler.NewMaterialHandler(materialService) + callRepository := repository.NewCallRepository(db) + callService := wire.ProvideCallService(callRepository, hub, config, db) callHandler := handler.NewCallHandler(callService) wsHandler := wire.ProvideWSHandler(hub, chatService, groupService, jwtService, callService) router := ProvideRouter(userHandler, postHandler, commentHandler, messageHandler, notificationHandler, uploadHandler, jwtService, pushHandler, systemMessageHandler, groupHandler, stickerHandler, voteHandler, channelHandler, scheduleHandler, roleHandler, adminUserHandler, adminPostHandler, adminCommentHandler, adminGroupHandler, adminDashboardHandler, adminLogHandler, qrCodeHandler, materialHandler, callHandler, logService, userActivityService, casbinService, wsHandler) diff --git a/go.sum b/go.sum index af86b37..60a4add 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/internal/dto/dto.go b/internal/dto/dto.go index aa82312..4ebf053 100644 --- a/internal/dto/dto.go +++ b/internal/dto/dto.go @@ -139,54 +139,54 @@ type PostImageResponse struct { // PostResponse 帖子响应(列表用) type PostResponse struct { - ID string `json:"id"` - UserID string `json:"user_id"` - ChannelID *string `json:"channel_id,omitempty"` - Title string `json:"title"` - Content string `json:"content"` - Images []PostImageResponse `json:"images"` - Status string `json:"status,omitempty"` - LikesCount int `json:"likes_count"` - CommentsCount int `json:"comments_count"` - FavoritesCount int `json:"favorites_count"` - SharesCount int `json:"shares_count"` - ViewsCount int `json:"views_count"` - IsPinned bool `json:"is_pinned"` - IsLocked bool `json:"is_locked"` - IsVote bool `json:"is_vote"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ContentEditedAt string `json:"content_edited_at,omitempty"` - Author *UserResponse `json:"author"` - IsLiked bool `json:"is_liked"` - IsFavorited bool `json:"is_favorited"` - Channel *PostChannelBrief `json:"channel,omitempty"` + ID string `json:"id"` + UserID string `json:"user_id"` + ChannelID *string `json:"channel_id,omitempty"` + Title string `json:"title"` + Content string `json:"content"` + Images []PostImageResponse `json:"images"` + Status string `json:"status,omitempty"` + LikesCount int `json:"likes_count"` + CommentsCount int `json:"comments_count"` + FavoritesCount int `json:"favorites_count"` + SharesCount int `json:"shares_count"` + ViewsCount int `json:"views_count"` + IsPinned bool `json:"is_pinned"` + IsLocked bool `json:"is_locked"` + IsVote bool `json:"is_vote"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ContentEditedAt string `json:"content_edited_at,omitempty"` + Author *UserResponse `json:"author"` + IsLiked bool `json:"is_liked"` + IsFavorited bool `json:"is_favorited"` + Channel *PostChannelBrief `json:"channel,omitempty"` } // PostDetailResponse 帖子详情响应 type PostDetailResponse struct { - ID string `json:"id"` - UserID string `json:"user_id"` - ChannelID *string `json:"channel_id,omitempty"` - Title string `json:"title"` - Content string `json:"content"` - Images []PostImageResponse `json:"images"` - Status string `json:"status"` - LikesCount int `json:"likes_count"` - CommentsCount int `json:"comments_count"` - FavoritesCount int `json:"favorites_count"` - SharesCount int `json:"shares_count"` - ViewsCount int `json:"views_count"` - IsPinned bool `json:"is_pinned"` - IsLocked bool `json:"is_locked"` - IsVote bool `json:"is_vote"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ContentEditedAt string `json:"content_edited_at,omitempty"` - Author *UserResponse `json:"author"` - IsLiked bool `json:"is_liked"` - IsFavorited bool `json:"is_favorited"` - Channel *PostChannelBrief `json:"channel,omitempty"` + ID string `json:"id"` + UserID string `json:"user_id"` + ChannelID *string `json:"channel_id,omitempty"` + Title string `json:"title"` + Content string `json:"content"` + Images []PostImageResponse `json:"images"` + Status string `json:"status"` + LikesCount int `json:"likes_count"` + CommentsCount int `json:"comments_count"` + FavoritesCount int `json:"favorites_count"` + SharesCount int `json:"shares_count"` + ViewsCount int `json:"views_count"` + IsPinned bool `json:"is_pinned"` + IsLocked bool `json:"is_locked"` + IsVote bool `json:"is_vote"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ContentEditedAt string `json:"content_edited_at,omitempty"` + Author *UserResponse `json:"author"` + IsLiked bool `json:"is_liked"` + IsFavorited bool `json:"is_favorited"` + Channel *PostChannelBrief `json:"channel,omitempty"` } // ==================== Comment DTOs ==================== @@ -687,13 +687,14 @@ type GroupAnnouncementListResponse struct { // WSEventResponse WebSocket事件响应结构体 // 用于后端推送消息给前端的标准格式 type WSEventResponse struct { - ID string `json:"id"` // 事件唯一ID (UUID) - Time int64 `json:"time"` // 时间戳 (毫秒) - Type string `json:"type"` // 事件类型 (message, notification, system等) - DetailType string `json:"detail_type"` // 详细类型 (private, group, like, comment等) - Seq string `json:"seq"` // 消息序列号 - Segments model.MessageSegments `json:"segments"` // 消息段数组 - SenderID string `json:"sender_id"` // 发送者用户ID + ID string `json:"id"` // 事件唯一ID (UUID) + Time int64 `json:"time"` // 时间戳 (毫秒) + Type string `json:"type"` // 事件类型 (message, notification, system等) + DetailType string `json:"detail_type"` // 详细类型 (private, group, like, comment等) + ConversationID string `json:"conversation_id"` // 会话ID + Seq string `json:"seq"` // 消息序列号 + Segments model.MessageSegments `json:"segments"` // 消息段数组 + SenderID string `json:"sender_id"` // 发送者用户ID } // ==================== WebSocket Request DTOs ==================== @@ -914,22 +915,22 @@ type WSResponse struct { // AdminPostListResponse 管理端帖子列表响应 type AdminPostListResponse struct { - ID string `json:"id"` - UserID string `json:"user_id"` - Title string `json:"title"` - Content string `json:"content"` - Images []PostImageResponse `json:"images"` - Status string `json:"status"` - LikesCount int `json:"likes_count,omitzero"` - CommentsCount int `json:"comments_count,omitzero"` - FavoritesCount int `json:"favorites_count,omitzero"` - ViewsCount int `json:"views_count,omitzero"` - IsPinned bool `json:"is_pinned"` - IsFeatured bool `json:"is_featured"` - IsLocked bool `json:"is_locked"` - RejectReason string `json:"reject_reason,omitempty"` - ReviewedAt string `json:"reviewed_at,omitempty"` - ReviewedBy string `json:"reviewed_by,omitempty"` + ID string `json:"id"` + UserID string `json:"user_id"` + Title string `json:"title"` + Content string `json:"content"` + Images []PostImageResponse `json:"images"` + Status string `json:"status"` + LikesCount int `json:"likes_count,omitzero"` + CommentsCount int `json:"comments_count,omitzero"` + FavoritesCount int `json:"favorites_count,omitzero"` + ViewsCount int `json:"views_count,omitzero"` + IsPinned bool `json:"is_pinned"` + IsFeatured bool `json:"is_featured"` + IsLocked bool `json:"is_locked"` + RejectReason string `json:"reject_reason,omitempty"` + ReviewedAt string `json:"reviewed_at,omitempty"` + ReviewedBy string `json:"reviewed_by,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` ContentEditedAt string `json:"content_edited_at,omitempty"` @@ -938,24 +939,24 @@ type AdminPostListResponse struct { // AdminPostDetailResponse 管理端帖子详情响应 type AdminPostDetailResponse struct { - ID string `json:"id"` - UserID string `json:"user_id"` - ChannelID *string `json:"channel_id,omitempty"` - Title string `json:"title"` - Content string `json:"content"` - Images []PostImageResponse `json:"images"` - Status string `json:"status"` - LikesCount int `json:"likes_count,omitzero"` - CommentsCount int `json:"comments_count,omitzero"` - FavoritesCount int `json:"favorites_count,omitzero"` - SharesCount int `json:"shares_count,omitzero"` - ViewsCount int `json:"views_count,omitzero"` - IsPinned bool `json:"is_pinned"` - IsFeatured bool `json:"is_featured"` - IsLocked bool `json:"is_locked"` - IsVote bool `json:"is_vote"` - RejectReason string `json:"reject_reason,omitempty"` - ReviewedAt string `json:"reviewed_at,omitempty"` + ID string `json:"id"` + UserID string `json:"user_id"` + ChannelID *string `json:"channel_id,omitempty"` + Title string `json:"title"` + Content string `json:"content"` + Images []PostImageResponse `json:"images"` + Status string `json:"status"` + LikesCount int `json:"likes_count,omitzero"` + CommentsCount int `json:"comments_count,omitzero"` + FavoritesCount int `json:"favorites_count,omitzero"` + SharesCount int `json:"shares_count,omitzero"` + ViewsCount int `json:"views_count,omitzero"` + IsPinned bool `json:"is_pinned"` + IsFeatured bool `json:"is_featured"` + IsLocked bool `json:"is_locked"` + IsVote bool `json:"is_vote"` + RejectReason string `json:"reject_reason,omitempty"` + ReviewedAt string `json:"reviewed_at,omitempty"` ReviewedBy string `json:"reviewed_by,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` diff --git a/internal/errors/app_errors.go b/internal/errors/app_errors.go index 26341b2..82e9b57 100644 --- a/internal/errors/app_errors.go +++ b/internal/errors/app_errors.go @@ -99,6 +99,34 @@ var ( ErrCannotModifyOwnRole = &AppError{Code: "CANNOT_MODIFY_OWN_ROLE", Message: "不能修改自己的角色"} ErrCannotModifySuperAdmin = &AppError{Code: "CANNOT_MODIFY_SUPER_ADMIN", Message: "不能修改超级管理员角色"} ErrCasbinInternal = &AppError{Code: "CASBIN_INTERNAL_ERROR", Message: "权限系统内部错误"} + + // 通话相关错误 + ErrCallNotFound = &AppError{Code: "CALL_NOT_FOUND", Message: "通话不存在"} + ErrCallNotActive = &AppError{Code: "CALL_NOT_ACTIVE", Message: "通话未激活"} + ErrCallInProgress = &AppError{Code: "CALL_IN_PROGRESS", Message: "用户之间已有通话"} + ErrNotCallParticipant = &AppError{Code: "NOT_CALL_PARTICIPANT", Message: "不是通话参与者"} + ErrInvalidCallState = &AppError{Code: "INVALID_CALL_STATE", Message: "通话状态无效"} + ErrCalleeOffline = &AppError{Code: "CALLEE_OFFLINE", Message: "对方不在线"} + ErrCallAlreadyAnswered = &AppError{Code: "CALL_ALREADY_ANSWERED", Message: "通话已在其他设备应答"} + + // 消息相关错误 + ErrConversationNotFound = &AppError{Code: "CONVERSATION_NOT_FOUND", Message: "会话不存在或无权限"} + ErrNotConversationMember = &AppError{Code: "NOT_CONVERSATION_MEMBER", Message: "不是会话参与者"} + ErrMessageNotFound = &AppError{Code: "MESSAGE_NOT_FOUND", Message: "消息不存在"} + ErrMessageAlreadyRecalled = &AppError{Code: "MESSAGE_ALREADY_RECALLED", Message: "消息已撤回"} + ErrMessageRecallTimeout = &AppError{Code: "MESSAGE_RECALL_TIMEOUT", Message: "消息撤回超时(2分钟)"} + ErrCannotSendMessage = &AppError{Code: "CANNOT_SEND_MESSAGE", Message: "无法发送消息"} + ErrCannotSendImage = &AppError{Code: "CANNOT_SEND_IMAGE", Message: "对方未关注你,暂不支持发送图片"} + ErrMessageLimitReached = &AppError{Code: "MESSAGE_LIMIT_REACHED", Message: "对方未关注你前,仅允许发送一条消息"} + ErrQRCodeSessionExpired = &AppError{Code: "QRCODE_SESSION_EXPIRED", Message: "二维码已过期"} + ErrQRCodeAlreadyScanned = &AppError{Code: "QRCODE_ALREADY_SCANNED", Message: "二维码已被扫描"} + ErrQRCodeInvalidStatus = &AppError{Code: "QRCODE_INVALID_STATUS", Message: "二维码状态无效"} + ErrPushNotImplemented = &AppError{Code: "PUSH_NOT_IMPLEMENTED", Message: "推送服务未实现"} + ErrPushQueueFull = &AppError{Code: "PUSH_QUEUE_FULL", Message: "推送队列已满"} + ErrUserOffline = &AppError{Code: "USER_OFFLINE", Message: "用户不在线"} + + // 学习资料相关错误 + ErrSubjectHasMaterials = &AppError{Code: "SUBJECT_HAS_MATERIALS", Message: "学科下存在资料,无法删除"} ) // Wrap 包装错误 diff --git a/internal/handler/message_handler.go b/internal/handler/message_handler.go index cb8a388..a67fc55 100644 --- a/internal/handler/message_handler.go +++ b/internal/handler/message_handler.go @@ -363,13 +363,14 @@ func (h *MessageHandler) HandleSendMessage(c *gin.Context) { // 构建 WSEventResponse 格式响应 wsResponse := dto.WSEventResponse{ - ID: msg.ID, - Time: msg.CreatedAt.UnixMilli(), - Type: "message", - DetailType: params.DetailType, - Seq: strconv.FormatInt(msg.Seq, 10), - Segments: params.Segments, - SenderID: userID, + ID: msg.ID, + Time: msg.CreatedAt.UnixMilli(), + Type: "message", + DetailType: params.DetailType, + ConversationID: conversationID, + Seq: strconv.FormatInt(msg.Seq, 10), + Segments: params.Segments, + SenderID: userID, } response.Success(c, wsResponse) diff --git a/internal/handler/user_handler.go b/internal/handler/user_handler.go index ec30178..7f5dc4c 100644 --- a/internal/handler/user_handler.go +++ b/internal/handler/user_handler.go @@ -39,10 +39,11 @@ type UserHandler struct { } // NewUserHandler 创建用户处理器 -func NewUserHandler(userService service.UserService, activityService service.UserActivityService) *UserHandler { +func NewUserHandler(userService service.UserService, activityService service.UserActivityService, logService *service.LogService) *UserHandler { return &UserHandler{ userService: userService, activityService: activityService, + logService: logService, } } @@ -56,11 +57,6 @@ func (h *UserHandler) SetActivityService(activityService service.UserActivitySer h.activityService = activityService } -// SetLogService 设置日志服务 -func (h *UserHandler) SetLogService(logService *service.LogService) { - h.logService = logService -} - // generateTokenID 生成Token ID func generateTokenID(token string) string { h := sha256.New() diff --git a/internal/handler/ws_handler.go b/internal/handler/ws_handler.go index c20d0ef..e3b86d3 100644 --- a/internal/handler/ws_handler.go +++ b/internal/handler/ws_handler.go @@ -16,6 +16,7 @@ import ( "go.uber.org/zap" "carrot_bbs/internal/dto" + apperrors "carrot_bbs/internal/errors" "carrot_bbs/internal/model" "carrot_bbs/internal/pkg/response" "carrot_bbs/internal/pkg/ws" @@ -338,13 +339,14 @@ func (h *WSHandler) handleChat(ctx context.Context, client *ws.Client, payload j } resp := dto.WSEventResponse{ - ID: message.ID, - Time: message.CreatedAt.UnixMilli(), - Type: "message", - DetailType: detailType, - Seq: strconv.FormatInt(message.Seq, 10), - Segments: req.Segments, - SenderID: client.UserID, + ID: message.ID, + Time: message.CreatedAt.UnixMilli(), + Type: "message", + DetailType: detailType, + ConversationID: req.ConversationID, + Seq: strconv.FormatInt(message.Seq, 10), + Segments: req.Segments, + SenderID: client.UserID, } msg := ws.ResponseMessage{ @@ -474,7 +476,7 @@ func (h *WSHandler) handleCallInvite(ctx context.Context, client *ws.Client, pay zap.String("callee_id", req.CalleeID), zap.Error(err), ) - if errors.Is(err, service.ErrCallInProgress) { + if errors.Is(err, apperrors.ErrCallInProgress) { h.wsHub.SendError(client, "call_in_progress", err.Error()) return } @@ -514,7 +516,7 @@ func (h *WSHandler) handleCallAnswer(ctx context.Context, client *ws.Client, pay call, err := h.callService.Accept(ctx, req.CallID, client.UserID) if err != nil { // === 区分已接听错误 === - if errors.Is(err, service.ErrCallAlreadyAnswered) { + if errors.Is(err, apperrors.ErrCallAlreadyAnswered) { h.wsHub.SendError(client, "call_already_answered", "通话已被其他设备接听") return } diff --git a/internal/service/admin_post_service.go b/internal/service/admin_post_service.go index 6a7a91a..7a00482 100644 --- a/internal/service/admin_post_service.go +++ b/internal/service/admin_post_service.go @@ -27,9 +27,6 @@ type AdminPostService interface { SetPostPin(ctx context.Context, postID string, isPinned bool) (*dto.AdminPostDetailResponse, error) // SetPostFeature 加精/取消加精帖子 SetPostFeature(ctx context.Context, postID string, isFeatured bool) (*dto.AdminPostDetailResponse, error) - - // 日志服务设置 - SetLogService(logService *LogService) } // adminPostServiceImpl 管理端帖子服务实现 @@ -40,19 +37,14 @@ type adminPostServiceImpl struct { } // NewAdminPostService 创建管理端帖子服务 -func NewAdminPostService(postRepo repository.PostRepository, cacheBackend cache.Cache) AdminPostService { +func NewAdminPostService(postRepo repository.PostRepository, cacheBackend cache.Cache, logService *LogService) AdminPostService { return &adminPostServiceImpl{ postRepo: postRepo, cache: cacheBackend, - logService: nil, + logService: logService, } } -// SetLogService 设置日志服务 -func (s *adminPostServiceImpl) SetLogService(logService *LogService) { - s.logService = logService -} - // GetPostList 获取帖子列表 func (s *adminPostServiceImpl) GetPostList(ctx context.Context, page, pageSize int, keyword, status, authorID, startDate, endDate string) ([]dto.AdminPostListResponse, int64, error) { query := repository.AdminPostListQuery{ diff --git a/internal/service/call_service.go b/internal/service/call_service.go index c173aff..a55abdf 100644 --- a/internal/service/call_service.go +++ b/internal/service/call_service.go @@ -3,11 +3,11 @@ package service import ( "context" "encoding/json" - "errors" "fmt" "time" "carrot_bbs/internal/config" + apperrors "carrot_bbs/internal/errors" "carrot_bbs/internal/model" "carrot_bbs/internal/pkg/ws" "carrot_bbs/internal/repository" @@ -16,16 +16,6 @@ import ( "gorm.io/gorm" ) -var ( - ErrCallNotFound = errors.New("call not found") - ErrCallNotActive = errors.New("call is not active") - ErrCallInProgress = errors.New("call already in progress between users") - ErrNotParticipant = errors.New("user is not a participant of this call") - ErrInvalidCallState = errors.New("invalid call state for this operation") - ErrCalleeOffline = errors.New("callee is offline") - ErrCallAlreadyAnswered = errors.New("call already answered on another device") -) - // 通话相关常量 const ( CallLifetimeMs = 60000 // 通话邀请有效期 60秒 (参考 Matrix) @@ -82,7 +72,7 @@ func NewCallService( func (s *callService) Invite(ctx context.Context, callerID, calleeID, conversationID, mediaType string) (*model.CallSession, bool, error) { active, err := s.callRepo.GetActiveCallByConversationID(conversationID) if err == nil && active != nil { - return nil, false, fmt.Errorf("%w: call %s", ErrCallInProgress, active.ID) + return nil, false, apperrors.Wrap(fmt.Errorf("call %s", active.ID), apperrors.ErrCallInProgress) } now := time.Now() @@ -152,12 +142,12 @@ func (s *callService) Invite(ctx context.Context, callerID, calleeID, conversati func (s *callService) Accept(ctx context.Context, callID, userID string) (*model.CallSession, error) { call, err := s.callRepo.GetCallByIDWithParticipants(callID) if err != nil { - return nil, fmt.Errorf("%w: %v", ErrCallNotFound, err) + return nil, apperrors.Wrap(err, apperrors.ErrCallNotFound) } // 检查用户是否是参与者 if !isParticipant(call, userID) { - return nil, ErrNotParticipant + return nil, apperrors.ErrNotCallParticipant } // === 修改:使用乐观锁更新状态 === @@ -176,7 +166,7 @@ func (s *callService) Accept(ctx context.Context, callID, userID string) (*model } if result.RowsAffected == 0 { // 没有更新任何行,说明通话已被其他设备接听 - return nil, ErrCallAlreadyAnswered + return nil, apperrors.ErrCallAlreadyAnswered } // 更新参与者状态 @@ -213,13 +203,13 @@ func (s *callService) Accept(ctx context.Context, callID, userID string) (*model func (s *callService) Reject(ctx context.Context, callID, userID string) error { call, err := s.callRepo.GetCallByIDWithParticipants(callID) if err != nil { - return fmt.Errorf("%w: %v", ErrCallNotFound, err) + return apperrors.Wrap(err, apperrors.ErrCallNotFound) } if call.Status != model.CallStatusCalling { - return ErrInvalidCallState + return apperrors.ErrInvalidCallState } if !isParticipant(call, userID) { - return ErrNotParticipant + return apperrors.ErrNotCallParticipant } now := time.Now() @@ -249,13 +239,13 @@ func (s *callService) Reject(ctx context.Context, callID, userID string) error { func (s *callService) Busy(ctx context.Context, callID, userID string) error { call, err := s.callRepo.GetCallByIDWithParticipants(callID) if err != nil { - return fmt.Errorf("%w: %v", ErrCallNotFound, err) + return apperrors.Wrap(err, apperrors.ErrCallNotFound) } if call.Status != model.CallStatusCalling { - return ErrInvalidCallState + return apperrors.ErrInvalidCallState } if !isParticipant(call, userID) { - return ErrNotParticipant + return apperrors.ErrNotCallParticipant } now := time.Now() @@ -276,14 +266,14 @@ func (s *callService) Busy(ctx context.Context, callID, userID string) error { func (s *callService) End(ctx context.Context, callID, userID string, reason string) (*model.CallSession, error) { call, err := s.callRepo.GetCallByIDWithParticipants(callID) if err != nil { - return nil, fmt.Errorf("%w: %v", ErrCallNotFound, err) + return nil, apperrors.Wrap(err, apperrors.ErrCallNotFound) } if !call.IsActive() { - return nil, ErrCallNotActive + return nil, apperrors.ErrCallNotActive } // 允许系统结束通话时 userID 为空 if userID != "" && !isParticipant(call, userID) { - return nil, ErrNotParticipant + return nil, apperrors.ErrNotCallParticipant } now := time.Now() @@ -337,13 +327,13 @@ func (s *callService) End(ctx context.Context, callID, userID string, reason str func (s *callService) RelaySignal(ctx context.Context, callID, fromUserID string, signalType string, payload json.RawMessage) error { call, err := s.callRepo.GetCallByIDWithParticipants(callID) if err != nil { - return fmt.Errorf("%w: %v", ErrCallNotFound, err) + return apperrors.Wrap(err, apperrors.ErrCallNotFound) } if !call.IsActive() { - return ErrCallNotActive + return apperrors.ErrCallNotActive } if !isParticipant(call, fromUserID) { - return ErrNotParticipant + return apperrors.ErrNotCallParticipant } participants, _ := s.callRepo.GetCallParticipants(callID) @@ -363,13 +353,13 @@ func (s *callService) RelaySignal(ctx context.Context, callID, fromUserID string func (s *callService) SetMuted(ctx context.Context, callID, userID string, muted bool) error { call, err := s.callRepo.GetCallByIDWithParticipants(callID) if err != nil { - return fmt.Errorf("%w: %v", ErrCallNotFound, err) + return apperrors.Wrap(err, apperrors.ErrCallNotFound) } if !call.IsActive() { - return ErrCallNotActive + return apperrors.ErrCallNotActive } if !isParticipant(call, userID) { - return ErrNotParticipant + return apperrors.ErrNotCallParticipant } participants, _ := s.callRepo.GetCallParticipants(callID) diff --git a/internal/service/comment_service.go b/internal/service/comment_service.go index b94a0b3..d5527c0 100644 --- a/internal/service/comment_service.go +++ b/internal/service/comment_service.go @@ -24,23 +24,18 @@ type CommentService struct { hookManager *hook.Manager } -func NewCommentService(commentRepo repository.CommentRepository, postRepo repository.PostRepository, systemMessageService SystemMessageService, postAIService *PostAIService, cacheBackend cache.Cache, hookManager *hook.Manager) *CommentService { +func NewCommentService(commentRepo repository.CommentRepository, postRepo repository.PostRepository, systemMessageService SystemMessageService, postAIService *PostAIService, cacheBackend cache.Cache, hookManager *hook.Manager, logService *LogService) *CommentService { return &CommentService{ commentRepo: commentRepo, postRepo: postRepo, systemMessageService: systemMessageService, cache: cacheBackend, postAIService: postAIService, - logService: nil, + logService: logService, hookManager: hookManager, } } -// SetLogService 设置日志服务 -func (s *CommentService) SetLogService(logService *LogService) { - s.logService = logService -} - // Create 创建评论 func (s *CommentService) Create(ctx context.Context, postID, userID, content string, parentID *string, images string, imageURLs []string) (*model.Comment, error) { if s.postAIService != nil { diff --git a/internal/service/post_service.go b/internal/service/post_service.go index 5a00f16..2ec6d0b 100644 --- a/internal/service/post_service.go +++ b/internal/service/post_service.go @@ -67,9 +67,7 @@ type PostService interface { // RecordShare 记录分享(仅已发布帖子计数 +1),返回最新 shares_count RecordShare(ctx context.Context, postID, userID string) (sharesCount int, err error) - // 日志服务设置 - SetLogService(logService *LogService) -} + } // postServiceImpl 帖子服务实现 type postServiceImpl struct { @@ -82,23 +80,18 @@ type postServiceImpl struct { hookManager *hook.Manager } -func NewPostService(postRepo repository.PostRepository, systemMessageService SystemMessageService, postAIService *PostAIService, cacheBackend cache.Cache, txManager repository.TransactionManager, hookManager *hook.Manager) PostService { +func NewPostService(postRepo repository.PostRepository, systemMessageService SystemMessageService, postAIService *PostAIService, cacheBackend cache.Cache, txManager repository.TransactionManager, hookManager *hook.Manager, logService *LogService) PostService { return &postServiceImpl{ postRepo: postRepo, systemMessageService: systemMessageService, cache: cacheBackend, postAIService: postAIService, txManager: txManager, - logService: nil, + logService: logService, hookManager: hookManager, } } -// SetLogService 设置日志服务 -func (s *postServiceImpl) SetLogService(logService *LogService) { - s.logService = logService -} - // PostListResult 帖子列表缓存结果 type PostListResult struct { Posts []*model.Post diff --git a/internal/service/push_service.go b/internal/service/push_service.go index d3d2de2..1c3dc54 100644 --- a/internal/service/push_service.go +++ b/internal/service/push_service.go @@ -65,7 +65,7 @@ type pushServiceImpl struct { pushRepo repository.PushRecordRepository deviceRepo repository.DeviceTokenRepository messageRepo repository.MessageRepository - wsHub *ws.Hub + wsHub *ws.Hub // 推送队列 pushQueue chan *pushTask @@ -90,7 +90,7 @@ func NewPushService( pushRepo: pushRepo, deviceRepo: deviceRepo, messageRepo: messageRepo, - wsHub: wsHub, + wsHub: wsHub, pushQueue: make(chan *pushTask, PushQueueSize), stopChan: make(chan struct{}), } @@ -190,13 +190,14 @@ func (s *pushServiceImpl) pushViaWebSocket(ctx context.Context, userID string, m segments := message.Segments event := &dto.WSEventResponse{ - ID: fmt.Sprintf("%s", message.ID), - Time: message.CreatedAt.UnixMilli(), - Type: "message", - DetailType: detailType, - Seq: fmt.Sprintf("%d", message.Seq), - Segments: segments, - SenderID: message.SenderID, + ID: fmt.Sprintf("%s", message.ID), + Time: message.CreatedAt.UnixMilli(), + Type: "message", + DetailType: detailType, + ConversationID: message.ConversationID, + Seq: fmt.Sprintf("%d", message.Seq), + Segments: segments, + SenderID: message.SenderID, } s.wsHub.PublishToUser(userID, "chat_message", map[string]interface{}{ diff --git a/internal/service/user_service.go b/internal/service/user_service.go index 270c122..d0093af 100644 --- a/internal/service/user_service.go +++ b/internal/service/user_service.go @@ -52,9 +52,6 @@ type UserService interface { UnblockUser(ctx context.Context, blockerID, blockedID string) error GetBlockedUsers(ctx context.Context, blockerID string, page, pageSize int) ([]*model.User, int64, error) IsBlocked(ctx context.Context, blockerID, blockedID string) (bool, error) - - // 日志服务设置 - SetLogService(logService *LogService) } // userServiceImpl 用户服务实现 @@ -71,20 +68,16 @@ func NewUserService( systemMessageService SystemMessageService, emailService EmailService, cacheBackend cache.Cache, + logService *LogService, ) UserService { return &userServiceImpl{ userRepo: userRepo, systemMessageService: systemMessageService, emailCodeService: NewEmailCodeService(emailService, cacheBackend), - logService: nil, + logService: logService, } } -// SetLogService 设置日志服务 -func (s *userServiceImpl) SetLogService(logService *LogService) { - s.logService = logService -} - // SendRegisterCode 发送注册验证码 func (s *userServiceImpl) SendRegisterCode(ctx context.Context, email, clientIP string) error { user, err := s.userRepo.GetByEmail(email) diff --git a/internal/wire/handler.go b/internal/wire/handler.go index f33a130..19e9384 100644 --- a/internal/wire/handler.go +++ b/internal/wire/handler.go @@ -30,8 +30,8 @@ var HandlerSet = wire.NewSet( handler.NewCallHandler, // 需要特殊处理的 Handler - ProvideUserHandler, - ProvidePostHandler, + handler.NewUserHandler, + handler.NewPostHandler, ProvideMessageHandler, ProvideSystemMessageHandler, ProvideGroupHandler, @@ -39,54 +39,6 @@ var HandlerSet = wire.NewSet( ProvideWSHandler, ) -// ProvideUserHandler 提供用户处理器 -func ProvideUserHandler( - userService service.UserService, - activityService service.UserActivityService, - postService service.PostService, - commentService *service.CommentService, - logService *service.LogService, -) *handler.UserHandler { - h := handler.NewUserHandler(userService, activityService) - h.SetLogService(logService) - - // 同时设置到其他服务 - if ps, ok := postService.(interface{ SetLogService(*service.LogService) }); ok { - ps.SetLogService(logService) - } - if commentService != nil { - commentService.SetLogService(logService) - } - - return h -} - -// ProvidePostHandler 提供帖子处理器 -func ProvidePostHandler( - postService service.PostService, - userService service.UserService, - channelService service.ChannelService, - logService *service.LogService, -) *handler.PostHandler { - h := handler.NewPostHandler(postService, userService, channelService) - if ps, ok := postService.(interface{ SetLogService(*service.LogService) }); ok { - ps.SetLogService(logService) - } - return h -} - -// ProvideAdminPostHandler 提供管理端帖子处理器 -func ProvideAdminPostHandler( - postService service.AdminPostService, - logService *service.LogService, -) *handler.AdminPostHandler { - h := handler.NewAdminPostHandler(postService) - if ps, ok := postService.(interface{ SetLogService(*service.LogService) }); ok { - ps.SetLogService(logService) - } - return h -} - // ProvideMessageHandler 提供消息处理器 func ProvideMessageHandler( chatService service.ChatService, diff --git a/internal/wire/service.go b/internal/wire/service.go index a4e079a..817bc80 100644 --- a/internal/wire/service.go +++ b/internal/wire/service.go @@ -115,8 +115,9 @@ func ProvidePostService( hookManager *hook.Manager, _ *hook.ModerationHooks, _ *hook.BuiltinHooks, + logService *service.LogService, ) service.PostService { - return service.NewPostService(postRepo, systemMessageService, postAIService, cacheBackend, txManager, hookManager) + return service.NewPostService(postRepo, systemMessageService, postAIService, cacheBackend, txManager, hookManager, logService) } func ProvideCommentService( @@ -126,8 +127,9 @@ func ProvideCommentService( postAIService *service.PostAIService, cacheBackend cache.Cache, hookManager *hook.Manager, + logService *service.LogService, ) *service.CommentService { - return service.NewCommentService(commentRepo, postRepo, systemMessageService, postAIService, cacheBackend, hookManager) + return service.NewCommentService(commentRepo, postRepo, systemMessageService, postAIService, cacheBackend, hookManager, logService) } // ProvideMessageService 提供消息服务 @@ -153,8 +155,9 @@ func ProvideUserService( systemMessageService service.SystemMessageService, emailService service.EmailService, cacheBackend cache.Cache, + logService *service.LogService, ) service.UserService { - return service.NewUserService(userRepo, systemMessageService, emailService, cacheBackend) + return service.NewUserService(userRepo, systemMessageService, emailService, cacheBackend, logService) } // ProvideStickerService 提供表情服务 @@ -247,8 +250,8 @@ func ProvideAdminUserService(userRepo repository.UserRepository) service.AdminUs } // ProvideAdminPostService 提供管理端帖子服务 -func ProvideAdminPostService(postRepo repository.PostRepository, cacheBackend cache.Cache) service.AdminPostService { - return service.NewAdminPostService(postRepo, cacheBackend) +func ProvideAdminPostService(postRepo repository.PostRepository, cacheBackend cache.Cache, logService *service.LogService) service.AdminPostService { + return service.NewAdminPostService(postRepo, cacheBackend, logService) } // ProvideAdminCommentService 提供管理端评论服务