// Package store defines MCP Nexus's persistence interfaces (ARCHITECTURE ยง8) // and an in-memory implementation used for Phase 1 and tests. A SQLite-backed // implementation lands in a later brick behind the same interfaces. package store import ( "context" "sort" "sync" "gitea.thetempleofdoom.com/drjones/mcp-gateway-nexus/internal/domain" ) // InstanceStore persists MCP instances (the observed/desired state the // reconciler manages). type InstanceStore interface { PutInstance(ctx context.Context, inst domain.MCPInstance) error GetInstance(ctx context.Context, id string) (domain.MCPInstance, bool, error) ListInstances(ctx context.Context) ([]domain.MCPInstance, error) DeleteInstance(ctx context.Context, id string) error } // Store aggregates all persistence surfaces. It will grow as later modules // (registry, identity, secrets, audit) come online. type Store interface { InstanceStore } // Memory is a thread-safe in-memory Store. type Memory struct { mu sync.RWMutex instances map[string]domain.MCPInstance } // NewMemory creates an empty in-memory store. func NewMemory() *Memory { return &Memory{instances: make(map[string]domain.MCPInstance)} } func (m *Memory) PutInstance(_ context.Context, inst domain.MCPInstance) error { m.mu.Lock() defer m.mu.Unlock() m.instances[inst.ID] = inst return nil } func (m *Memory) GetInstance(_ context.Context, id string) (domain.MCPInstance, bool, error) { m.mu.RLock() defer m.mu.RUnlock() inst, ok := m.instances[id] return inst, ok, nil } func (m *Memory) ListInstances(_ context.Context) ([]domain.MCPInstance, error) { m.mu.RLock() defer m.mu.RUnlock() out := make([]domain.MCPInstance, 0, len(m.instances)) for _, inst := range m.instances { out = append(out, inst) } sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID }) return out, nil } func (m *Memory) DeleteInstance(_ context.Context, id string) error { m.mu.Lock() defer m.mu.Unlock() delete(m.instances, id) return nil } var _ Store = (*Memory)(nil)