Files
l-ui/internal/web/runtime/manager.go
T

85 lines
2.0 KiB
Go

package runtime
import (
"sync"
)
// Manager dispatches inbound/client writes to a Runtime. In the lite
// master every node is agent-managed and the master runs no local core,
// so the only production runtime is the no-op Local: writes land in the
// database and agent nodes converge by pulling their config. The
// override seams remain for tests that exercise the dispatch paths with
// a stub runtime.
type Manager struct {
local Runtime
mu sync.RWMutex
overrides map[int]Runtime // test-only: forces RuntimeFor to return a stub
localOverride Runtime // test-only: forces RuntimeFor(nil) to return a stub
}
func NewManager() *Manager {
return &Manager{
local: NewLocal(),
}
}
// SetRuntimeOverride makes RuntimeFor(nodeID) return rt instead of the
// local runtime. Test seam for exercising node-dispatch paths without a
// network node; pass nil rt to clear.
func (m *Manager) SetRuntimeOverride(nodeID int, rt Runtime) {
m.mu.Lock()
defer m.mu.Unlock()
if rt == nil {
delete(m.overrides, nodeID)
return
}
if m.overrides == nil {
m.overrides = make(map[int]Runtime)
}
m.overrides[nodeID] = rt
}
// SetLocalRuntimeOverride makes RuntimeFor(nil) return rt instead of the
// real local runtime. Test seam for exercising the local dispatch path
// without a running child process; pass nil rt to clear.
func (m *Manager) SetLocalRuntimeOverride(rt Runtime) {
m.mu.Lock()
defer m.mu.Unlock()
m.localOverride = rt
}
func (m *Manager) RuntimeFor(nodeID *int) (Runtime, error) {
m.mu.RLock()
defer m.mu.RUnlock()
if nodeID == nil {
if m.localOverride != nil {
return m.localOverride, nil
}
return m.local, nil
}
if rt, ok := m.overrides[*nodeID]; ok {
return rt, nil
}
return m.local, nil
}
func (m *Manager) Local() Runtime { return m.local }
var (
managerMu sync.RWMutex
manager *Manager
)
func SetManager(m *Manager) {
managerMu.Lock()
defer managerMu.Unlock()
manager = m
}
func GetManager() *Manager {
managerMu.RLock()
defer managerMu.RUnlock()
return manager
}