218 lines
5.0 KiB
Go
218 lines
5.0 KiB
Go
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)
|