spark-server/internal/module/moment/model/memory.go
2026-09-18 17:51:42 +08:00

248 lines
5.6 KiB
Go

package model
import (
"context"
"sort"
"sync"
"spark-server/internal/module/moment/entity"
"spark-server/internal/pkg/errs"
)
type likeKey struct {
PostID int64
UserID int64
}
type hideKey struct {
UserID int64
PeerID int64
}
// MemoryRepo is an in-process Moments store for tests and empty-DSN bring-up.
type MemoryRepo struct {
mu sync.Mutex
posts map[int64]*entity.Post
audience map[int64][]int64
likes map[likeKey]*entity.Like
comments map[int64]*entity.Comment
notices map[int64]*entity.Notice
settings map[int64]*entity.Settings
hides map[hideKey]*entity.Hide
}
func NewMemoryRepo() *MemoryRepo {
return &MemoryRepo{
posts: make(map[int64]*entity.Post),
audience: make(map[int64][]int64),
likes: make(map[likeKey]*entity.Like),
comments: make(map[int64]*entity.Comment),
notices: make(map[int64]*entity.Notice),
settings: make(map[int64]*entity.Settings),
hides: make(map[hideKey]*entity.Hide),
}
}
func (m *MemoryRepo) GetPost(_ context.Context, id int64) (*entity.Post, error) {
m.mu.Lock()
defer m.mu.Unlock()
row, ok := m.posts[id]
if !ok {
return nil, errs.ErrNotFound
}
return clonePost(row), nil
}
func (m *MemoryRepo) ListByAuthors(_ context.Context, authorIDs []int64, cursor int64, limit int) ([]*entity.Post, error) {
m.mu.Lock()
defer m.mu.Unlock()
allow := toSet(authorIDs)
out := make([]*entity.Post, 0)
for _, row := range m.posts {
if row.Status != entity.StatusNormal || !allow[row.UserID] {
continue
}
if cursor > 0 && row.ID >= cursor {
continue
}
out = append(out, clonePost(row))
}
sort.Slice(out, func(i, j int) bool { return out[i].ID > out[j].ID })
if limit > 0 && len(out) > limit {
out = out[:limit]
}
return out, nil
}
func (m *MemoryRepo) ListByAuthor(ctx context.Context, authorID, cursor int64, limit int) ([]*entity.Post, error) {
return m.ListByAuthors(ctx, []int64{authorID}, cursor, limit)
}
func (m *MemoryRepo) ListAudience(_ context.Context, postIDs []int64) (map[int64][]int64, error) {
m.mu.Lock()
defer m.mu.Unlock()
allow := toSet(postIDs)
out := make(map[int64][]int64)
for id, peers := range m.audience {
if !allow[id] {
continue
}
out[id] = append([]int64(nil), peers...)
}
return out, nil
}
func (m *MemoryRepo) ListLikes(_ context.Context, postIDs []int64) (map[int64][]*entity.Like, error) {
m.mu.Lock()
defer m.mu.Unlock()
allow := toSet(postIDs)
out := make(map[int64][]*entity.Like)
for _, like := range m.likes {
if !allow[like.PostID] {
continue
}
cp := *like
out[like.PostID] = append(out[like.PostID], &cp)
}
for id := range out {
sort.Slice(out[id], func(i, j int) bool { return out[id][i].CreatedAtMS < out[id][j].CreatedAtMS })
}
return out, nil
}
func (m *MemoryRepo) ListComments(_ context.Context, postIDs []int64) (map[int64][]*entity.Comment, error) {
m.mu.Lock()
defer m.mu.Unlock()
allow := toSet(postIDs)
out := make(map[int64][]*entity.Comment)
for _, c := range m.comments {
if !allow[c.PostID] {
continue
}
out[c.PostID] = append(out[c.PostID], cloneComment(c))
}
for id := range out {
sort.Slice(out[id], func(i, j int) bool { return out[id][i].ID < out[id][j].ID })
}
return out, nil
}
func (m *MemoryRepo) GetComment(_ context.Context, id int64) (*entity.Comment, error) {
m.mu.Lock()
defer m.mu.Unlock()
row, ok := m.comments[id]
if !ok {
return nil, errs.ErrNotFound
}
return cloneComment(row), nil
}
func (m *MemoryRepo) GetSettings(_ context.Context, userID int64) (*entity.Settings, error) {
m.mu.Lock()
defer m.mu.Unlock()
if row, ok := m.settings[userID]; ok {
cp := *row
return &cp, nil
}
return entity.DefaultSettings(userID), nil
}
func (m *MemoryRepo) ListSettings(_ context.Context, userIDs []int64) (map[int64]*entity.Settings, error) {
m.mu.Lock()
defer m.mu.Unlock()
allow := toSet(userIDs)
out := make(map[int64]*entity.Settings)
for id, row := range m.settings {
if allow[id] {
cp := *row
out[id] = &cp
}
}
return out, nil
}
func (m *MemoryRepo) ListHides(_ context.Context, userID int64) ([]*entity.Hide, error) {
m.mu.Lock()
defer m.mu.Unlock()
out := make([]*entity.Hide, 0)
for _, h := range m.hides {
if h.UserID == userID {
cp := *h
out = append(out, &cp)
}
}
return out, nil
}
func (m *MemoryRepo) HideHimIDs(_ context.Context, userID int64) ([]int64, error) {
m.mu.Lock()
defer m.mu.Unlock()
out := make([]int64, 0)
for _, h := range m.hides {
if h.UserID == userID && h.HideHim {
out = append(out, h.PeerID)
}
}
return out, nil
}
func (m *MemoryRepo) HideMeFromIDs(_ context.Context, viewerID int64) ([]int64, error) {
m.mu.Lock()
defer m.mu.Unlock()
out := make([]int64, 0)
for _, h := range m.hides {
if h.PeerID == viewerID && h.HideMe {
out = append(out, h.UserID)
}
}
return out, nil
}
func (m *MemoryRepo) ListNotices(_ context.Context, userID, cursor int64, limit int) ([]*entity.Notice, error) {
m.mu.Lock()
defer m.mu.Unlock()
out := make([]*entity.Notice, 0)
for _, n := range m.notices {
if n.ToUserID != userID {
continue
}
if cursor > 0 && n.ID >= cursor {
continue
}
cp := *n
out = append(out, &cp)
}
sort.Slice(out, func(i, j int) bool { return out[i].ID > out[j].ID })
if limit > 0 && len(out) > limit {
out = out[:limit]
}
return out, nil
}
func toSet(ids []int64) map[int64]bool {
out := make(map[int64]bool, len(ids))
for _, id := range ids {
out[id] = true
}
return out
}
func clonePost(p *entity.Post) *entity.Post {
if p == nil {
return nil
}
cp := *p
if p.Content != nil {
cp.Content = append([]byte(nil), p.Content...)
}
return &cp
}
func cloneComment(c *entity.Comment) *entity.Comment {
if c == nil {
return nil
}
cp := *c
return &cp
}