thread-master/apps/backend/internal/module/studio/repository/memory.go

328 lines
7.5 KiB
Go

package repository
import (
"context"
"sort"
"sync"
"apps/backend/internal/module/studio/domain"
)
type MemoryStore struct {
mu sync.Mutex
personas map[string]*domain.Persona
active map[int64]string
plays map[string]*domain.Play
outbox map[string]*domain.OutboxBundle
ownPosts map[string]*domain.OwnPost
mentions map[string]*domain.Mention
syncMeta map[int64]*domain.SyncMeta
}
func NewMemory() *MemoryStore {
return &MemoryStore{
personas: map[string]*domain.Persona{},
active: map[int64]string{},
plays: map[string]*domain.Play{},
outbox: map[string]*domain.OutboxBundle{},
ownPosts: map[string]*domain.OwnPost{},
mentions: map[string]*domain.Mention{},
syncMeta: map[int64]*domain.SyncMeta{},
}
}
func (s *MemoryStore) SavePersona(_ context.Context, p *domain.Persona) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *p
s.personas[p.ID] = &cp
return nil
}
func (s *MemoryStore) GetPersona(_ context.Context, id string) (*domain.Persona, error) {
s.mu.Lock()
defer s.mu.Unlock()
p, ok := s.personas[id]
if !ok {
return nil, domain.ErrNotFound
}
cp := *p
return &cp, nil
}
func (s *MemoryStore) ListPersonas(_ context.Context, ownerUID int64) ([]*domain.Persona, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.Persona
for _, p := range s.personas {
if p.OwnerUID == ownerUID {
cp := *p
out = append(out, &cp)
}
}
sort.Slice(out, func(i, j int) bool { return out[i].UpdatedAt > out[j].UpdatedAt })
return out, nil
}
func (s *MemoryStore) DeletePersona(_ context.Context, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.personas[id]; !ok {
return domain.ErrNotFound
}
delete(s.personas, id)
return nil
}
func (s *MemoryStore) GetActivePersonaID(_ context.Context, ownerUID int64) (string, error) {
s.mu.Lock()
defer s.mu.Unlock()
return s.active[ownerUID], nil
}
func (s *MemoryStore) SetActivePersonaID(_ context.Context, ownerUID int64, personaID string) error {
s.mu.Lock()
defer s.mu.Unlock()
s.active[ownerUID] = personaID
return nil
}
func (s *MemoryStore) SavePlay(_ context.Context, p *domain.Play) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *p
if p.Steps != nil {
cp.Steps = append([]domain.PlayStep(nil), p.Steps...)
}
if p.CastAccountIDs != nil {
cp.CastAccountIDs = append([]string(nil), p.CastAccountIDs...)
}
if p.TargetExternal != nil {
te := *p.TargetExternal
cp.TargetExternal = &te
}
s.plays[p.ID] = &cp
return nil
}
func (s *MemoryStore) GetPlay(_ context.Context, id string) (*domain.Play, error) {
s.mu.Lock()
defer s.mu.Unlock()
p, ok := s.plays[id]
if !ok {
return nil, domain.ErrNotFound
}
return copyPlay(p), nil
}
func (s *MemoryStore) ListPlays(_ context.Context, ownerUID int64) ([]*domain.Play, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.Play
for _, p := range s.plays {
if p.OwnerUID == ownerUID {
out = append(out, copyPlay(p))
}
}
sort.Slice(out, func(i, j int) bool { return out[i].UpdatedAt > out[j].UpdatedAt })
return out, nil
}
func (s *MemoryStore) DeletePlay(_ context.Context, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.plays[id]; !ok {
return domain.ErrNotFound
}
delete(s.plays, id)
return nil
}
func copyPlay(p *domain.Play) *domain.Play {
cp := *p
if p.Steps != nil {
cp.Steps = append([]domain.PlayStep(nil), p.Steps...)
}
if p.CastAccountIDs != nil {
cp.CastAccountIDs = append([]string(nil), p.CastAccountIDs...)
}
if p.TargetExternal != nil {
te := *p.TargetExternal
cp.TargetExternal = &te
}
return &cp
}
func (s *MemoryStore) SaveOutbox(_ context.Context, b *domain.OutboxBundle) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *b
if b.Steps != nil {
cp.Steps = append([]domain.OutboxStep(nil), b.Steps...)
}
s.outbox[b.ID] = &cp
return nil
}
func (s *MemoryStore) GetOutbox(_ context.Context, id string) (*domain.OutboxBundle, error) {
s.mu.Lock()
defer s.mu.Unlock()
b, ok := s.outbox[id]
if !ok {
return nil, domain.ErrNotFound
}
return copyOutbox(b), nil
}
func (s *MemoryStore) ListOutbox(_ context.Context, ownerUID int64) ([]*domain.OutboxBundle, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.OutboxBundle
for _, b := range s.outbox {
if b.OwnerUID == ownerUID {
out = append(out, copyOutbox(b))
}
}
sort.Slice(out, func(i, j int) bool { return out[i].UpdatedAt > out[j].UpdatedAt })
return out, nil
}
func (s *MemoryStore) DeleteOutbox(_ context.Context, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.outbox[id]; !ok {
return domain.ErrNotFound
}
delete(s.outbox, id)
return nil
}
func (s *MemoryStore) ListAllOutbox(_ context.Context) ([]*domain.OutboxBundle, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.OutboxBundle
for _, b := range s.outbox {
out = append(out, copyOutbox(b))
}
return out, nil
}
func copyOutbox(b *domain.OutboxBundle) *domain.OutboxBundle {
cp := *b
if b.Steps != nil {
cp.Steps = append([]domain.OutboxStep(nil), b.Steps...)
}
return &cp
}
func (s *MemoryStore) SaveOwnPost(_ context.Context, p *domain.OwnPost) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *p
if p.Replies != nil {
cp.Replies = append([]domain.OwnPostReply(nil), p.Replies...)
}
s.ownPosts[p.ID] = &cp
return nil
}
func (s *MemoryStore) GetOwnPost(_ context.Context, id string) (*domain.OwnPost, error) {
s.mu.Lock()
defer s.mu.Unlock()
p, ok := s.ownPosts[id]
if !ok {
return nil, domain.ErrNotFound
}
cp := *p
if p.Replies != nil {
cp.Replies = append([]domain.OwnPostReply(nil), p.Replies...)
}
return &cp, nil
}
func (s *MemoryStore) DeleteOwnPost(_ context.Context, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.ownPosts, id)
return nil
}
func (s *MemoryStore) ListOwnPosts(_ context.Context, ownerUID int64, accountID string) ([]*domain.OwnPost, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.OwnPost
for _, p := range s.ownPosts {
if p.OwnerUID != ownerUID {
continue
}
if accountID != "" && p.AccountID != accountID {
continue
}
cp := *p
if p.Replies != nil {
cp.Replies = append([]domain.OwnPostReply(nil), p.Replies...)
}
out = append(out, &cp)
}
sort.Slice(out, func(i, j int) bool { return out[i].PublishedAt > out[j].PublishedAt })
return out, nil
}
func (s *MemoryStore) GetSyncMeta(_ context.Context, ownerUID int64) (*domain.SyncMeta, error) {
s.mu.Lock()
defer s.mu.Unlock()
m, ok := s.syncMeta[ownerUID]
if !ok {
return &domain.SyncMeta{OwnerUID: ownerUID}, nil
}
cp := *m
return &cp, nil
}
func (s *MemoryStore) SetSyncMeta(_ context.Context, m *domain.SyncMeta) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *m
s.syncMeta[m.OwnerUID] = &cp
return nil
}
func (s *MemoryStore) SaveMention(_ context.Context, m *domain.Mention) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *m
s.mentions[m.ID] = &cp
return nil
}
func (s *MemoryStore) GetMention(_ context.Context, id string) (*domain.Mention, error) {
s.mu.Lock()
defer s.mu.Unlock()
m, ok := s.mentions[id]
if !ok {
return nil, domain.ErrNotFound
}
cp := *m
return &cp, nil
}
func (s *MemoryStore) ListMentions(_ context.Context, ownerUID int64, accountID string) ([]*domain.Mention, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.Mention
for _, m := range s.mentions {
if m.OwnerUID != ownerUID {
continue
}
if accountID != "" && m.AccountID != accountID {
continue
}
cp := *m
out = append(out, &cp)
}
sort.Slice(out, func(i, j int) bool { return out[i].CreatedAt > out[j].CreatedAt })
return out, nil
}
var _ domain.Repository = (*MemoryStore)(nil)