chat/internal/usecase/message.go

116 lines
3.2 KiB
Go

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
}