// registry.go:适配器注册表 + Health 聚合 + init 并发探活。 // 能力路由数据源(scheduler 侧按 intent+region+render 标签匹配)。 package dock import ( "context" "fmt" "sync" "onesvm.com/onesvm/browser-server/internal/contract" ) // Registry 适配器注册表(map 名字 → 适配器;并发安全只读)。 type Registry struct { mu sync.RWMutex items map[string]contract.DockAdapter order []string // 稳定遍历序(路由优先级依赖) } // NewRegistry 空注册表。 func NewRegistry() *Registry { return &Registry{items: map[string]contract.DockAdapter{}} } // Register 注册(重名覆盖)。 func (r *Registry) Register(a contract.DockAdapter) { r.mu.Lock() defer r.mu.Unlock() name := adapterDisplayName(a) if _, exists := r.items[name]; !exists { r.order = append(r.order, name) } r.items[name] = a } // Get 按名取。 func (r *Registry) Get(name string) (contract.DockAdapter, bool) { r.mu.RLock() defer r.mu.RUnlock() a, ok := r.items[name] return a, ok } // Names 全部名字(注册稳定序)。 func (r *Registry) Names() []string { r.mu.RLock() defer r.mu.RUnlock() out := make([]string, len(r.order)) copy(out, r.order) return out } // All 全部适配器(注册稳定序)。 func (r *Registry) All() []contract.DockAdapter { r.mu.RLock() defer r.mu.RUnlock() out := make([]contract.DockAdapter, 0, len(r.order)) for _, k := range r.order { out = append(out, r.items[k]) } return out } // InitAll 并发 Init(探活;全部完成才返回,单适配器失败不阻塞其它——Health 摘除)。 func (r *Registry) InitAll(ctx context.Context) map[string]error { var wg sync.WaitGroup errs := make(map[string]error) var mu sync.Mutex for _, a := range r.All() { wg.Add(1) go func(a contract.DockAdapter) { defer wg.Done() err := a.Init(ctx) mu.Lock() if err != nil { errs[adapterDisplayName(a)] = err } mu.Unlock() }(a) } wg.Wait() return errs } // HealthAll 聚合健康:名字 → Health。 func (r *Registry) HealthAll() map[string]contract.Health { out := map[string]contract.Health{} for _, a := range r.All() { out[adapterDisplayName(a)] = a.Health() } return out } // HealthyAdapters 按 intent 过滤出健康适配器名(Health().ok=false 摘除走降级, // design §4.5 降级条款 2)。 func (r *Registry) HealthyAdapters(intent string) []string { var out []string for _, a := range r.All() { caps := a.Capabilities() for _, i := range caps.Intents { if i == intent && a.Health().OK { out = append(out, adapterDisplayName(a)) break } } } return out } // adapterDisplayName 适配器展示名(Caps 无名字字段,由接口可选扩展携带; // 默认回退 intent 首个 + 序列稳定名)。 func adapterDisplayName(a contract.DockAdapter) string { if n, ok := a.(interface{ Name() string }); ok { return n.Name() } return fmt.Sprintf("adapter-%p", a) } // TeardownAll 逆序优雅停机。 func (r *Registry) TeardownAll(ctx context.Context) { all := r.All() for i := len(all) - 1; i >= 0; i-- { _ = all[i].Teardown(ctx) } }