153 lines
3.5 KiB
Go
153 lines
3.5 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
|
|
"spark-server/internal/module/friend/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
type edgeKey struct {
|
|
UserID int64
|
|
FriendID int64
|
|
}
|
|
|
|
type requestKey struct {
|
|
From int64
|
|
To int64
|
|
}
|
|
|
|
// MemoryRepo is an in-process friend store for tests and empty-DSN bring-up.
|
|
type MemoryRepo struct {
|
|
mu sync.Mutex
|
|
relations map[edgeKey]*entity.Relation
|
|
requests map[int64]*entity.Request
|
|
byPair map[requestKey]int64
|
|
reports []*entity.Report
|
|
}
|
|
|
|
func NewMemoryRepo() *MemoryRepo {
|
|
return &MemoryRepo{
|
|
relations: make(map[edgeKey]*entity.Relation),
|
|
requests: make(map[int64]*entity.Request),
|
|
byPair: make(map[requestKey]int64),
|
|
}
|
|
}
|
|
|
|
func (m *MemoryRepo) GetRelation(_ context.Context, userID, friendID int64) (*entity.Relation, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
rel, ok := m.relations[edgeKey{UserID: userID, FriendID: friendID}]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *rel
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) ListFriends(_ context.Context, userID int64, limit int) ([]*entity.Relation, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
limit = entity.ClampLimit(limit)
|
|
out := make([]*entity.Relation, 0)
|
|
for _, rel := range m.relations {
|
|
if rel.UserID == userID && rel.Status == entity.StatusFriend {
|
|
cp := *rel
|
|
out = append(out, &cp)
|
|
}
|
|
}
|
|
sort.Slice(out, func(i, j int) bool {
|
|
if out[i].Pinned != out[j].Pinned {
|
|
return out[i].Pinned
|
|
}
|
|
return out[i].CreatedAt.After(out[j].CreatedAt)
|
|
})
|
|
if len(out) > limit {
|
|
out = out[:limit]
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetRequest(_ context.Context, id int64) (*entity.Request, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
req, ok := m.requests[id]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *req
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetRequestByPair(_ context.Context, from, to int64) (*entity.Request, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
id, ok := m.byPair[requestKey{From: from, To: to}]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *m.requests[id]
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) UpsertRequest(_ context.Context, req *entity.Request) error {
|
|
if req == nil || req.FromUser <= 0 || req.ToUser <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
key := requestKey{From: req.FromUser, To: req.ToUser}
|
|
if id, ok := m.byPair[key]; ok {
|
|
cur := m.requests[id]
|
|
cur.Source = req.Source
|
|
cur.Reason = req.Reason
|
|
cur.Remark = req.Remark
|
|
cur.Status = req.Status
|
|
cur.UpdatedAt = req.UpdatedAt
|
|
*req = *cur
|
|
return nil
|
|
}
|
|
cp := *req
|
|
m.requests[req.ID] = &cp
|
|
m.byPair[key] = req.ID
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) ListIncoming(_ context.Context, toUserID int64, status entity.RequestStatus, limit int) ([]*entity.Request, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
limit = entity.ClampLimit(limit)
|
|
out := make([]*entity.Request, 0)
|
|
for _, req := range m.requests {
|
|
if req.ToUser != toUserID {
|
|
continue
|
|
}
|
|
if status > 0 && req.Status != status {
|
|
continue
|
|
}
|
|
cp := *req
|
|
out = append(out, &cp)
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].UpdatedAt.After(out[j].UpdatedAt) })
|
|
if len(out) > limit {
|
|
out = out[:limit]
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) rejectPendingLocked(a, b int64, at time.Time) {
|
|
for _, req := range m.requests {
|
|
if req.Status != entity.RequestPending {
|
|
continue
|
|
}
|
|
pair := (req.FromUser == a && req.ToUser == b) || (req.FromUser == b && req.ToUser == a)
|
|
if pair {
|
|
req.Status = entity.RequestRejected
|
|
req.UpdatedAt = at
|
|
}
|
|
}
|
|
}
|