feat(module): add four-phase Module interface and registry
This commit is contained in:
56
internal/module/registry.go
Normal file
56
internal/module/registry.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Registry holds all known modules keyed by Meta.ID.
|
||||
type Registry struct {
|
||||
mu sync.RWMutex
|
||||
modules map[string]Module
|
||||
}
|
||||
|
||||
// NewRegistry returns an empty registry.
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{modules: make(map[string]Module)}
|
||||
}
|
||||
|
||||
// Register adds a module. Returns an error if the ID is already present
|
||||
// or empty. Safe for concurrent use.
|
||||
func (r *Registry) Register(m Module) error {
|
||||
id := m.Meta().ID
|
||||
if id == "" {
|
||||
return fmt.Errorf("module has empty ID")
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if _, dup := r.modules[id]; dup {
|
||||
return fmt.Errorf("module %q already registered", id)
|
||||
}
|
||||
r.modules[id] = m
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the module with the given ID, or (nil, false) if absent.
|
||||
func (r *Registry) Get(id string) (Module, bool) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
m, ok := r.modules[id]
|
||||
return m, ok
|
||||
}
|
||||
|
||||
// All returns all registered modules sorted by ID for determinism.
|
||||
func (r *Registry) All() []Module {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
out := make([]Module, 0, len(r.modules))
|
||||
for _, m := range r.modules {
|
||||
out = append(out, m)
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
return out[i].Meta().ID < out[j].Meta().ID
|
||||
})
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user