package usecase import ( "chat/internal/domain/entity" "chat/internal/domain/repository" "chat/internal/domain/usecase" "chat/internal/library/centrifugo" "chat/internal/utils" "context" "fmt" "time" "github.com/zeromicro/go-zero/core/logx" ) type messageUseCase struct { messageRepo repository.MessageRepository matchmakingRepo repository.MatchmakingRepository centrifugoClient *centrifugo.Client } // NewMessageUseCase 創建新的訊息 UseCase func NewMessageUseCase( messageRepo repository.MessageRepository, matchmakingRepo repository.MatchmakingRepository, centrifugoClient *centrifugo.Client, ) usecase.MessageUseCase { return &messageUseCase{ messageRepo: messageRepo, matchmakingRepo: matchmakingRepo, centrifugoClient: centrifugoClient, } } // SendMessage 發送訊息 func (u *messageUseCase) SendMessage(ctx context.Context, roomID string, uid string, content string, clientMsgID string) error { // 驗證訊息內容不為空 if content == "" { return fmt.Errorf("message content cannot be empty") } // 驗證使用者是否在房間中 isMember, err := u.matchmakingRepo.IsRoomMember(ctx, roomID, uid) if err != nil { logx.Errorf("Failed to check room membership: roomID=%s, uid=%s, error=%v", roomID, uid, err) return fmt.Errorf("failed to check room membership: %w", err) } if !isMember { logx.Errorf("User is not a member of the room: roomID=%s, uid=%s", roomID, uid) return fmt.Errorf("user is not a member of the room") } // 生成訊息 ID messageID := utils.GenerateMessageID() if clientMsgID != "" { messageID = clientMsgID } // 建立訊息實體 now := time.Now() msg := &entity.Message{ RoomID: roomID, BucketDay: utils.GetBucketDay(now), TS: now.UnixNano() / 1e6, // milliseconds MessageID: messageID, UID: uid, Content: content, } // 儲存到 Cassandra if err := u.messageRepo.Insert(ctx, msg); err != nil { return fmt.Errorf("failed to save message: %w", err) } // 發布到 Centrifugo channel := fmt.Sprintf("room:%s", roomID) messageData := map[string]interface{}{ "message_id": msg.MessageID, "uid": msg.UID, "content": msg.Content, "timestamp": msg.TS, "room_id": msg.RoomID, } if err := u.centrifugoClient.PublishJSON(channel, messageData); err != nil { logx.Errorf("failed to publish message to Centrifugo: %v", err) // 不返回錯誤,因為訊息已經儲存 } return nil } // ListMessages 查詢訊息列表(分頁) func (u *messageUseCase) ListMessages(ctx context.Context, roomID string, uid string, pageSize int, pageIndex int) ([]entity.Message, int64, error) { // 驗證使用者是否在房間中 isMember, err := u.matchmakingRepo.IsRoomMember(ctx, roomID, uid) if err != nil { return nil, 0, fmt.Errorf("failed to check room membership: %w", err) } if !isMember { return nil, 0, fmt.Errorf("user is not a member of the room") } // 取得今天的 bucket_day bucketDay := utils.GetTodayBucketDay() // 查詢訊息 messages, totalPages, err := u.messageRepo.ListByRoom(ctx, roomID, bucketDay, pageSize, pageIndex) if err != nil { return nil, 0, fmt.Errorf("failed to list messages: %w", err) } return messages, totalPages, nil }