Files
AskaEth 4a2d276881
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(capability): 转码能力包(vendor 纯 Go AMR-NB 解码器 + 黄金向量逐样本对照 + 8 哨兵 + 注册面)
2026-10-05 13:02:28 +08:00

87 lines
2.7 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.
package transcode
import (
"fmt"
"sort"
"sync"
)
// Registry 承载「哪些 源→目标 可用」(design/25 §1.3.2 第一层)。它是**包内**的
// 编解码器注册表,与全局能力注册表(internal/capability/registry)是两件事:
// 后者表达「agent 可选用的能力 + 门控策略」,前者表达「本能力认识哪几条路」。
//
// 新增一种格式 = 往这里多一个注册项(见 codecs.go 的 DefaultCodecs);
// 并发安全。
type Registry struct {
mu sync.RWMutex
codecs map[route]Codec
}
// route 是「源→目标」这一对,作注册表的键。用结构体而非字符串拼接:拼接会让
// 格式名里出现分隔符时产生歧义(`a->b` 与 `a-` + `>b`)。
type route struct {
from Format
to Format
}
// NewRegistry 返回一个空且并发安全的编解码器注册表。
func NewRegistry() *Registry {
return &Registry{codecs: make(map[route]Codec)}
}
// Register 注册一条转换路。nil、源/目标为空、源等于目标都返回 ErrInvalidCodec;
// 同一对重复注册返回 ErrDuplicate。
func (r *Registry) Register(c Codec) error {
if c == nil {
return fmt.Errorf("transcode: register codec: %w: nil codec", ErrInvalidCodec)
}
from, to := c.From(), c.To()
if from == "" || to == "" {
return fmt.Errorf("transcode: register codec %q -> %q: %w: empty format", from, to, ErrInvalidCodec)
}
if from == to {
return fmt.Errorf("transcode: register codec %q -> %q: %w: identity route", from, to, ErrInvalidCodec)
}
r.mu.Lock()
defer r.mu.Unlock()
key := route{from: from, to: to}
if _, exists := r.codecs[key]; exists {
return fmt.Errorf("transcode: register codec %q -> %q: %w", from, to, ErrDuplicate)
}
r.codecs[key] = c
return nil
}
// Lookup 返回 from→to 这条路上的编解码器。没有这条路时 ok 为 false。
func (r *Registry) Lookup(from, to Format) (Codec, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
c, ok := r.codecs[route{from: from, to: to}]
return c, ok
}
// Formats 返回当前注册涉及的全部格式(源与目标去重后的并集,已排序)。
// 它是「发现」面:调用方据此知道本能力认识哪些格式名。
func (r *Registry) Formats() []Format {
r.mu.RLock()
defer r.mu.RUnlock()
seen := make(map[Format]struct{}, len(r.codecs)*2)
for key := range r.codecs {
seen[key.from] = struct{}{}
seen[key.to] = struct{}{}
}
out := make([]Format, 0, len(seen))
for f := range seen {
out = append(out, f)
}
sort.Slice(out, func(i, j int) bool { return out[i] < out[j] })
return out
}
// Len 返回已注册的「源→目标」路数。供启动期自检与测试断言使用。
func (r *Registry) Len() int {
r.mu.RLock()
defer r.mu.RUnlock()
return len(r.codecs)
}