116 lines
3.2 KiB
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
|
|
}
|
|
|