package router import ( "context" "fmt" "sync" "go.uber.org/zap" "iop/apps/node/internal/adapters" "iop/apps/node/internal/runtime" ) type MutableRouter interface { runtime.Router SetRegistry(*adapters.Registry) } type defaultRouter struct { mu sync.RWMutex registry *adapters.Registry logger *zap.Logger } // New returns a MutableRouter that resolves requests to registered adapters. func New(reg *adapters.Registry, logger *zap.Logger) MutableRouter { return &defaultRouter{registry: reg, logger: logger} } func (r *defaultRouter) SetRegistry(reg *adapters.Registry) { r.mu.Lock() defer r.mu.Unlock() r.registry = reg } func (r *defaultRouter) resolveWithRegistry(req runtime.RunRequest, reg *adapters.Registry) (runtime.ExecutionSpec, error) { adapterName := req.Adapter if adapterName == "" { return runtime.ExecutionSpec{}, fmt.Errorf("router: adapter is required") } if _, err := reg.Lookup(adapterName); err != nil { return runtime.ExecutionSpec{}, fmt.Errorf("router: %w", err) } spec := runtime.ExecutionSpec{ RunID: req.RunID, Adapter: adapterName, Target: req.Target, SessionID: req.SessionID, SessionMode: req.SessionMode, Background: req.Background, Workspace: req.Workspace, Policy: req.Policy, Input: req.Input, TimeoutSec: req.TimeoutSec, Metadata: req.Metadata, } r.logger.Debug("resolved execution spec", zap.String("run_id", req.RunID), zap.String("adapter", spec.Adapter), zap.String("target", spec.Target), ) return spec, nil } func (r *defaultRouter) Resolve(_ context.Context, req runtime.RunRequest) (runtime.ExecutionSpec, error) { r.mu.RLock() reg := r.registry r.mu.RUnlock() return r.resolveWithRegistry(req, reg) } func (r *defaultRouter) ResolveAdapter(ctx context.Context, req runtime.RunRequest) (runtime.ExecutionSpec, runtime.Adapter, error) { r.mu.RLock() reg := r.registry r.mu.RUnlock() spec, err := r.resolveWithRegistry(req, reg) if err != nil { return runtime.ExecutionSpec{}, nil, err } adapter, err := reg.Lookup(spec.Adapter) if err != nil { return runtime.ExecutionSpec{}, nil, fmt.Errorf("router: %w", err) } return spec, adapter, nil } func (r *defaultRouter) LookupAdapter(adapterName string) (runtime.Adapter, error) { r.mu.RLock() reg := r.registry r.mu.RUnlock() return reg.Lookup(adapterName) } func (r *defaultRouter) GetAdapter(adapterName string) (runtime.Adapter, bool) { r.mu.RLock() reg := r.registry r.mu.RUnlock() a, err := reg.Lookup(adapterName) if err != nil { return nil, false } return a, true }