0f6aea796c
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71 lines
1.5 KiB
Go
71 lines
1.5 KiB
Go
package module
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
// Registry is a concurrency-safe in-memory index of loaded manifests.
|
|
// It's held as a shared component by both Controller and Target.
|
|
type Registry struct {
|
|
mu sync.RWMutex
|
|
modules map[string]*Manifest
|
|
}
|
|
|
|
// NewRegistry returns an empty registry.
|
|
func NewRegistry() *Registry {
|
|
return &Registry{modules: make(map[string]*Manifest)}
|
|
}
|
|
|
|
// LoadDir scans dir for modules and inserts them. Duplicate IDs are rejected.
|
|
func (r *Registry) LoadDir(dir string) error {
|
|
ms, err := LoadDir(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
for _, m := range ms {
|
|
if _, exists := r.modules[m.ID]; exists {
|
|
return fmt.Errorf("duplicate module id %q in %s", m.ID, dir)
|
|
}
|
|
r.modules[m.ID] = m
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Put inserts or replaces a manifest.
|
|
func (r *Registry) Put(m *Manifest) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.modules[m.ID] = m
|
|
}
|
|
|
|
// Get returns the manifest for id, or (nil, false) if unknown.
|
|
func (r *Registry) Get(id string) (*Manifest, bool) {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
m, ok := r.modules[id]
|
|
return m, ok
|
|
}
|
|
|
|
// List returns all manifests sorted by id.
|
|
func (r *Registry) List() []*Manifest {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
out := make([]*Manifest, 0, len(r.modules))
|
|
for _, m := range r.modules {
|
|
out = append(out, m)
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
|
|
return out
|
|
}
|
|
|
|
// Len returns the number of modules currently registered.
|
|
func (r *Registry) Len() int {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
return len(r.modules)
|
|
}
|