onesvm-browser-server/server/internal/dock/registry.go
chii eb972dfa93 feat: 落地 browser-server 控制面并打通 mgr1 海外订阅
单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 15:05:12 +08:00

125 lines
3.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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)
}
}