Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout. Co-authored-by: Cursor <cursoragent@cursor.com>
73 lines
2.0 KiB
Go
73 lines
2.0 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"spark-server/internal/module/conversation/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
type IDGen interface {
|
|
NextID() (int64, error)
|
|
}
|
|
|
|
type P2PRepository interface {
|
|
GetP2P(ctx context.Context, userA, userB int64) (*entity.Conversation, error)
|
|
CreateP2P(ctx context.Context, c *entity.Conversation, p2p *entity.P2P, members []*entity.Member) error
|
|
UpdateLastMsg(ctx context.Context, id, msgID, atMS int64) error
|
|
}
|
|
|
|
// P2PService opens the unique 1:1 conversation for a user pair.
|
|
type P2PService struct {
|
|
repo P2PRepository
|
|
ids IDGen
|
|
}
|
|
|
|
func NewP2PService(repo P2PRepository, ids IDGen) *P2PService {
|
|
return &P2PService{repo: repo, ids: ids}
|
|
}
|
|
|
|
func (s *P2PService) EnsureP2P(ctx context.Context, userA, userB int64) (int64, error) {
|
|
if s == nil || s.repo == nil || s.ids == nil || userA <= 0 || userB <= 0 || userA == userB {
|
|
return 0, errs.ErrInvalidArgument
|
|
}
|
|
if c, err := s.repo.GetP2P(ctx, userA, userB); err == nil {
|
|
return c.ID, nil
|
|
} else if !errors.Is(err, errs.ErrNotFound) {
|
|
return 0, err
|
|
}
|
|
id, err := s.ids.NextID()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
now := time.Now()
|
|
small, big := entity.OrderUsers(userA, userB)
|
|
conv := &entity.Conversation{ID: id, Type: entity.TypeP2P, LastMsgAt: now.UnixMilli()}
|
|
p2p := &entity.P2P{UserSmall: small, UserBig: big, ConversationID: id}
|
|
joined := now.UnixMilli()
|
|
members := []*entity.Member{
|
|
{ConversationID: id, UserID: userA, JoinedAtMS: joined},
|
|
{ConversationID: id, UserID: userB, JoinedAtMS: joined},
|
|
}
|
|
if err := s.repo.CreateP2P(ctx, conv, p2p, members); err != nil {
|
|
if errors.Is(err, errs.ErrDuplicate) {
|
|
c, err := s.repo.GetP2P(ctx, userA, userB)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return c.ID, nil
|
|
}
|
|
return 0, err
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (s *P2PService) UpdateLastMsg(ctx context.Context, conversationID, msgID, atMS int64) error {
|
|
if s == nil || s.repo == nil {
|
|
return errs.ErrAvailable
|
|
}
|
|
return s.repo.UpdateLastMsg(ctx, conversationID, msgID, atMS)
|
|
}
|