123 lines
2.9 KiB
Go
123 lines
2.9 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
"spark-server/internal/module/inbox/entity"
|
|
)
|
|
|
|
type dialog struct {
|
|
unread map[int64]int64
|
|
read map[int64]int64
|
|
unreadCnt map[int64]int64
|
|
}
|
|
|
|
// MemoryStore is an in-process inbox for tests.
|
|
type MemoryStore struct {
|
|
mu sync.Mutex
|
|
byUser map[int64]*dialog
|
|
previews map[int64][]byte
|
|
}
|
|
|
|
func NewMemoryStore() *MemoryStore {
|
|
return &MemoryStore{byUser: make(map[int64]*dialog), previews: make(map[int64][]byte)}
|
|
}
|
|
|
|
func (s *MemoryStore) user(uid int64) *dialog {
|
|
d, ok := s.byUser[uid]
|
|
if !ok {
|
|
d = &dialog{unread: map[int64]int64{}, read: map[int64]int64{}, unreadCnt: map[int64]int64{}}
|
|
s.byUser[uid] = d
|
|
}
|
|
return d
|
|
}
|
|
|
|
func (s *MemoryStore) TouchUnread(_ context.Context, userID, conversationID, score int64) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
d := s.user(userID)
|
|
delete(d.read, conversationID)
|
|
d.unread[conversationID] = score
|
|
return nil
|
|
}
|
|
|
|
func (s *MemoryStore) TouchRead(_ context.Context, userID, conversationID, score int64) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
d := s.user(userID)
|
|
delete(d.unread, conversationID)
|
|
d.read[conversationID] = score
|
|
return nil
|
|
}
|
|
|
|
func (s *MemoryStore) IncrUnread(_ context.Context, userID, conversationID, delta int64) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
d := s.user(userID)
|
|
d.unreadCnt[conversationID] += delta
|
|
return nil
|
|
}
|
|
|
|
func (s *MemoryStore) SetPreview(_ context.Context, conversationID int64, preview []byte) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.previews[conversationID] = append([]byte(nil), preview...)
|
|
return nil
|
|
}
|
|
|
|
func (s *MemoryStore) ListUpdatedSince(_ context.Context, userID, score int64, limit int) ([]entity.DialogHit, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
d := s.user(userID)
|
|
var out []entity.DialogHit
|
|
seen := map[int64]struct{}{}
|
|
add := func(cid, sc int64) {
|
|
if sc <= score {
|
|
return
|
|
}
|
|
if _, ok := seen[cid]; ok {
|
|
return
|
|
}
|
|
seen[cid] = struct{}{}
|
|
out = append(out, entity.DialogHit{ConversationID: cid, Score: sc})
|
|
}
|
|
for cid, sc := range d.unread {
|
|
add(cid, sc)
|
|
}
|
|
for cid, sc := range d.read {
|
|
add(cid, sc)
|
|
}
|
|
if limit > 0 && len(out) > limit {
|
|
out = out[:limit]
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (s *MemoryStore) LoadDialogs(_ context.Context, userID int64, hits []entity.DialogHit) ([]entity.Dialog, error) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
out := make([]entity.Dialog, 0, len(hits))
|
|
for _, hit := range hits {
|
|
out = append(out, entity.Dialog{
|
|
ConversationID: hit.ConversationID,
|
|
Score: hit.Score,
|
|
Unread: s.user(userID).unreadCnt[hit.ConversationID],
|
|
Preview: append([]byte(nil), s.previews[hit.ConversationID]...),
|
|
})
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (s *MemoryStore) Preview(conversationID int64) []byte {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return append([]byte(nil), s.previews[conversationID]...)
|
|
}
|
|
|
|
func (s *MemoryStore) UnreadCount(userID, conversationID int64) int64 {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return s.user(userID).unreadCnt[conversationID]
|
|
}
|