SYNC_INBOX 补 conversation_type、peer_id、group_id 和 last_read_msg_id。历史消息在 sender 为 0 时用 peer_id 定位对方。已读清未读时保留会话 ZSET 分数,避免被毫秒时间戳冲到游标后面。 Co-authored-by: Cursor <cursoragent@cursor.com>
75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
conventity "spark-server/internal/module/conversation/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
type HistoryRequest struct {
|
|
ConversationID int64
|
|
LastMsgID int64
|
|
Limit int
|
|
}
|
|
|
|
type HistoryResponse struct {
|
|
Items []*Item `json:"items"`
|
|
HasMore bool `json:"has_more"`
|
|
}
|
|
|
|
func (s *Service) GetHistory(ctx context.Context, userID int64, req HistoryRequest) (*HistoryResponse, error) {
|
|
if !s.ready() || userID <= 0 {
|
|
return nil, errs.ErrUnauthorized
|
|
}
|
|
if req.ConversationID <= 0 {
|
|
return nil, errs.ErrInvalidArgument
|
|
}
|
|
if _, err := s.chats.GetMember(ctx, req.ConversationID, userID); err != nil {
|
|
if errors.Is(err, errs.ErrNotFound) {
|
|
return nil, errs.ErrForbidden
|
|
}
|
|
return nil, err
|
|
}
|
|
limit := req.Limit
|
|
if limit <= 0 || limit > defaultHistoryLimit {
|
|
limit = defaultHistoryLimit
|
|
}
|
|
rows, err := s.repo.ListByConversation(ctx, req.ConversationID, userID, req.LastMsgID, limit+1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hasMore := len(rows) > limit
|
|
if hasMore {
|
|
rows = rows[:limit]
|
|
}
|
|
peer := s.viewerPeer(ctx, userID, req.ConversationID)
|
|
items := make([]*Item, 0, len(rows))
|
|
for _, row := range rows {
|
|
item := itemOf(row)
|
|
item.PeerID = peer
|
|
items = append(items, item)
|
|
}
|
|
return &HistoryResponse{Items: items, HasMore: hasMore}, nil
|
|
}
|
|
|
|
// viewerPeer is the other member of a P2P conversation. Group chats stay 0; use group_id.
|
|
// System messages keep sender_id=0 and receiver_id=0; this field is how the viewer finds the peer.
|
|
func (s *Service) viewerPeer(ctx context.Context, viewerID, conversationID int64) int64 {
|
|
conv, err := s.chats.Get(ctx, conversationID)
|
|
if err != nil || conv == nil || conv.Type != conventity.TypeP2P {
|
|
return 0
|
|
}
|
|
ids, err := s.chats.ListMemberIDs(ctx, conversationID)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
for _, id := range ids {
|
|
if id > 0 && id != viewerID {
|
|
return id
|
|
}
|
|
}
|
|
return 0
|
|
}
|