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

218 lines
5.0 KiB
Go
Raw Normal View History

2026-07-13 01:15:30 +00:00
package repository
import (
"context"
"sync"
"apps/backend/internal/module/inspire/domain"
)
type MemoryStore struct {
mu sync.Mutex
trends map[int64][]*domain.TrendItem
elements map[string]*domain.Element
sessions map[string]*domain.Session // by session id
active map[int64]string // owner -> session id
}
func NewMemory() *MemoryStore {
return &MemoryStore{
trends: map[int64][]*domain.TrendItem{},
elements: map[string]*domain.Element{},
sessions: map[string]*domain.Session{},
active: map[int64]string{},
}
}
func (s *MemoryStore) ListTrends(_ context.Context, ownerUID int64) ([]*domain.TrendItem, error) {
s.mu.Lock()
defer s.mu.Unlock()
list := s.trends[ownerUID]
out := make([]*domain.TrendItem, 0, len(list))
for _, t := range list {
cp := *t
if t.Keywords != nil {
cp.Keywords = append([]string(nil), t.Keywords...)
}
if t.Samples != nil {
cp.Samples = append([]string(nil), t.Samples...)
}
out = append(out, &cp)
}
return out, nil
}
func (s *MemoryStore) SaveTrends(_ context.Context, ownerUID int64, items []*domain.TrendItem) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := make([]*domain.TrendItem, 0, len(items))
for _, t := range items {
x := *t
if t.Keywords != nil {
x.Keywords = append([]string(nil), t.Keywords...)
}
if t.Samples != nil {
x.Samples = append([]string(nil), t.Samples...)
}
cp = append(cp, &x)
}
s.trends[ownerUID] = cp
return nil
}
func (s *MemoryStore) ListElements(_ context.Context, ownerUID int64) ([]*domain.Element, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.Element
for _, e := range s.elements {
if e.OwnerUID == ownerUID {
cp := *e
out = append(out, &cp)
}
}
return out, nil
}
func (s *MemoryStore) SaveElement(_ context.Context, e *domain.Element) error {
s.mu.Lock()
defer s.mu.Unlock()
cp := *e
s.elements[e.ID] = &cp
return nil
}
func (s *MemoryStore) DeleteElement(_ context.Context, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.elements[id]; !ok {
return domain.ErrNotFound
}
delete(s.elements, id)
return nil
}
func (s *MemoryStore) GetElement(_ context.Context, id string) (*domain.Element, error) {
s.mu.Lock()
defer s.mu.Unlock()
e, ok := s.elements[id]
if !ok {
return nil, domain.ErrNotFound
}
cp := *e
return &cp, nil
}
func (s *MemoryStore) ListSessions(_ context.Context, ownerUID int64) ([]*domain.Session, error) {
s.mu.Lock()
defer s.mu.Unlock()
var out []*domain.Session
for _, sess := range s.sessions {
if sess.OwnerUID == ownerUID {
out = append(out, copySession(sess))
}
}
// sort by updated_at desc
for i := 0; i < len(out); i++ {
for j := i + 1; j < len(out); j++ {
if out[j].UpdatedAt > out[i].UpdatedAt {
out[i], out[j] = out[j], out[i]
}
}
}
if len(out) > 50 {
out = out[:50]
}
return out, nil
}
func (s *MemoryStore) GetSession(_ context.Context, ownerUID int64) (*domain.Session, error) {
s.mu.Lock()
defer s.mu.Unlock()
if id, ok := s.active[ownerUID]; ok {
if sess, ok2 := s.sessions[id]; ok2 && sess.OwnerUID == ownerUID {
return copySession(sess), nil
}
}
var best *domain.Session
for _, sess := range s.sessions {
if sess.OwnerUID != ownerUID {
continue
}
if best == nil || sess.UpdatedAt > best.UpdatedAt {
best = sess
}
}
if best == nil {
return nil, domain.ErrNotFound
}
s.active[ownerUID] = best.ID
return copySession(best), nil
}
func (s *MemoryStore) GetSessionByID(_ context.Context, ownerUID int64, id string) (*domain.Session, error) {
s.mu.Lock()
defer s.mu.Unlock()
sess, ok := s.sessions[id]
if !ok || sess.OwnerUID != ownerUID {
return nil, domain.ErrNotFound
}
return copySession(sess), nil
}
func (s *MemoryStore) SaveSession(_ context.Context, sess *domain.Session) error {
s.mu.Lock()
defer s.mu.Unlock()
s.sessions[sess.ID] = copySession(sess)
return nil
}
func (s *MemoryStore) DeleteSessionByID(_ context.Context, ownerUID int64, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
sess, ok := s.sessions[id]
if !ok || sess.OwnerUID != ownerUID {
return domain.ErrNotFound
}
delete(s.sessions, id)
if s.active[ownerUID] == id {
delete(s.active, ownerUID)
}
return nil
}
func (s *MemoryStore) GetActiveSessionID(_ context.Context, ownerUID int64) (string, error) {
s.mu.Lock()
defer s.mu.Unlock()
id, ok := s.active[ownerUID]
if !ok || id == "" {
return "", domain.ErrNotFound
}
return id, nil
}
func (s *MemoryStore) SetActiveSessionID(_ context.Context, ownerUID int64, sessionID string) error {
s.mu.Lock()
defer s.mu.Unlock()
s.active[ownerUID] = sessionID
return nil
}
func copySession(sess *domain.Session) *domain.Session {
cp := *sess
if sess.Messages != nil {
cp.Messages = append([]domain.ChatMessage(nil), sess.Messages...)
for i := range cp.Messages {
if sess.Messages[i].Draft != nil {
d := *sess.Messages[i].Draft
cp.Messages[i].Draft = &d
}
}
}
if sess.PinnedElementIDs != nil {
cp.PinnedElementIDs = append([]string(nil), sess.PinnedElementIDs...)
}
return &cp
}
var _ domain.Repository = (*MemoryStore)(nil)