docs(gateway): WS 帧门相关 11 个文件的注释改中文(只改注释,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」。本次先把本会话动过的文件就地翻; 不做全仓一次性翻译,存量按包分批排期(见 工作小结.md 待办)。 范围:ws_frame_scope.go / ws_frame_scope_test.go / broadcast.go / ws_hub_turn.go / ws_hub_message_event.go / session_read.go / server.go / ws_hub_stream_scope_test.go / history_write_broadcast_test.go / mood_test.go / extra_test.go 含中文的整行注释 18 → 382。 校验(判据 = "只改注释、零代码字节改动"): - `git diff -U0 | 排除 +++/--- | 排除注释行/空行/行尾注释` → 为空 - 独立实现:两侧剥掉注释后逐行比对代码文本 → 11/11 文件全等,不一致数 0 - 行尾注释 7 行逐条列出,代码列与原文逐字节相同(gofmt 未要求重排) - gofmt -l 干净;全树 go build/vet 绿;go test ./... = 58 包 ok / 0 FAIL; linux/amd64 + darwin/arm64 交叉编译绿 语义未删减:部分折行英文长句合并为更少行,故整行注释数 438 → 399。
This commit is contained in:
1 parent
770a83c3fb
commit
fe1ff33115
11 files changed
+392
-431
No files matched your search
@@ -14,45 +14,42 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||||
)
|
||||
|
||||
// These tests lock the design/11 §7.1 frame gate: a viewer connection may follow
|
||||
// the session state machine but must never receive content, while owner and admin
|
||||
// keep both classes. frameScopeCases is the design/11 §7.1 table in code — every
|
||||
// frame type named there, published on the subject that really produces it — so a
|
||||
// classification mistake (a content frame made public, or a state signal made
|
||||
// private) fails here instead of leaking silently.
|
||||
// 这些测试锁住 design/11 §7.1 的帧门:viewer 连接可以跟随会话状态机,
|
||||
// 但绝不可收到内容,而 owner 与 admin 两类都保留。frameScopeCases 是
|
||||
// design/11 §7.1 表在代码中的体现 —— 表中点名的每种帧类型,都发布在
|
||||
// 真正产生它的主题上 —— 因此分类错误(内容帧被公开,或状态信号被
|
||||
// 私有化)会在这里失败,而不是静默泄露。
|
||||
|
||||
// frameScopeCase is one row of the design/11 §7.1 table.
|
||||
// frameScopeCase 是 design/11 §7.1 表的一行。
|
||||
type frameScopeCase struct {
|
||||
typ string // downstream frame type
|
||||
subject string // bus subject that produces it
|
||||
payload any // payload published on that subject
|
||||
public bool // 「状态机信号」: no content → every authenticated connection
|
||||
typ string // 下行帧类型
|
||||
subject string // 产生它的 bus 主题
|
||||
payload any // 发布在该主题上的载荷
|
||||
public bool // 「状态机信号」:不含内容 → 每个已认证连接
|
||||
}
|
||||
|
||||
// scopeSentinel is published last: the bus runs one worker per subscription
|
||||
// sequentially, so a connection that has seen the sentinel has already been
|
||||
// offered every frame published before it. That turns "the viewer received nothing
|
||||
// else" into an exact count instead of a guessed idle window.
|
||||
// scopeSentinel 最后发布:bus 每个订阅跑一个 worker 且按序处理,因此
|
||||
// 已经看到哨兵的连接必定已经被投递过它之前发布的每一个帧。这把
|
||||
// 「viewer 没有收到别的」从猜测的空闲窗口变成精确计数。
|
||||
const scopeSentinel = EventSessionIdle
|
||||
|
||||
// The batch pacing used by publishFrameScopeCases, kept well under the hub's
|
||||
// wsSendBuffer depth so a burst never trips the slow-client drop.
|
||||
// publishFrameScopeCases 使用的批次节流,远低于 hub 的 wsSendBuffer
|
||||
// 深度,因此一次突发永不触发慢客户端丢弃。
|
||||
const (
|
||||
scopePaceFrames = 4
|
||||
scopePacePause = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
// scopeRead is the outcome of one connection's reader goroutine.
|
||||
// scopeRead 是一个连接读取 goroutine 的结果。
|
||||
type scopeRead struct {
|
||||
role auth.Role
|
||||
types []string
|
||||
err error
|
||||
}
|
||||
|
||||
// frameScopeCases returns the design/11 §7.1 table. Relayed frames use their real
|
||||
// ws.<type> subject; stream frames publish the real model.StreamEvent the loop
|
||||
// emits on ws.stream, so the test drives the production path
|
||||
// bus → relay → broadcast instead of a hand-built frame.
|
||||
// frameScopeCases 返回 design/11 §7.1 表。转发帧使用它们真实的 ws.<type>
|
||||
// 主题;流帧发布 loop 在 ws.stream 上发出的真实 model.StreamEvent,因此
|
||||
// 测试驱动的是生产路径 bus → relay → broadcast,而不是手工构造的帧。
|
||||
func frameScopeCases() []frameScopeCase {
|
||||
relayed := func(typ string, public bool) frameScopeCase {
|
||||
return frameScopeCase{typ: typ, subject: wsPrefix + typ, payload: map[string]any{"sessionId": "web"}, public: public}
|
||||
@@ -113,12 +110,11 @@ func frameScopeCases() []frameScopeCase {
|
||||
}
|
||||
}
|
||||
|
||||
// TestWSFrameScopePerRole drives the whole design/11 §7.1 table through real
|
||||
// WebSocket connections with real role tokens: owner and admin receive every frame
|
||||
// of the table, while the viewer receives exactly the whitelisted state signals, in
|
||||
// publish order. The viewer assertions the design calls out by name (message.delta /
|
||||
// thinking.delta / message_persisted / graph_update / mood denied, session_idle
|
||||
// delivered) are re-stated explicitly so the contract is readable in the test.
|
||||
// TestWSFrameScopePerRole 用真实角色 token 经真实 WebSocket 连接驱动
|
||||
// 整张 design/11 §7.1 表:owner 与 admin 收到表中的每一帧,而 viewer
|
||||
// 恰好收到白名单状态信号,且按发布顺序。设计点名的 viewer 断言
|
||||
// (message.delta / thinking.delta / message_persisted / graph_update /
|
||||
// mood 被拒,session_idle 被投递)在此显式复述,使契约在测试中可读。
|
||||
func TestWSFrameScopePerRole(t *testing.T) {
|
||||
t.Parallel()
|
||||
cases := frameScopeCases()
|
||||
@@ -140,9 +136,9 @@ func TestWSFrameScopePerRole(t *testing.T) {
|
||||
auth.RoleViewer: len(public),
|
||||
}
|
||||
|
||||
// The clients drain on their own goroutines while the batch is published: the
|
||||
// hub drops frames for a client whose send buffer is full (its slow-client
|
||||
// policy), so a client that only started reading afterwards would lose the tail.
|
||||
// 各客户端在批次发布期间于自己的 goroutine 上排空:hub 会丢弃
|
||||
// 发送缓冲已满的客户端的帧(其慢客户端策略),因此之后才开始
|
||||
// 读取的客户端会丢掉尾部。
|
||||
results := make(chan scopeRead, len(conns))
|
||||
for role, want := range wants {
|
||||
role, want := role, want
|
||||
@@ -177,11 +173,10 @@ func TestWSFrameScopePerRole(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHubBroadcastScopeMatrix is the per-frame-type × per-role matrix, driven
|
||||
// directly through the delivery entry so every row of the table is asserted in
|
||||
// isolation (a leaked frame would otherwise be hard to attribute). claims are set
|
||||
// explicitly per role, so a default-deny regression shows up as the viewer losing
|
||||
// the frame it is entitled to.
|
||||
// TestHubBroadcastScopeMatrix 是「每种帧类型 × 每种角色」矩阵,直接经
|
||||
// 投递入口驱动,使表中每一行都被孤立断言(否则泄露的帧难以归因)。
|
||||
// claims 按角色显式设置,因此默认拒绝的回归会表现为 viewer 丢掉它
|
||||
// 本应收到的帧。
|
||||
func TestHubBroadcastScopeMatrix(t *testing.T) {
|
||||
t.Parallel()
|
||||
hb := newTestHub(nil, nil)
|
||||
@@ -217,11 +212,10 @@ func TestHubBroadcastScopeMatrix(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestFrameScopeAllowsExactlyTheStateSignals pins the two properties that keep the
|
||||
// gate from drifting: an unclassified frame type is never public (so a frame added
|
||||
// by a later milestone cannot leak by omission), and the public set is exactly the
|
||||
// state signals design/11 §7.1 registers — widening it means editing the design, the
|
||||
// gate and this table together.
|
||||
// TestFrameScopeAllowsExactlyTheStateSignals 钉住两条使帧门不漂移的
|
||||
// 性质:未分类的帧类型永不是公开的(因此后续里程碑新增的帧不会因
|
||||
// 漏分类而泄露),且公开集合恰好是 design/11 §7.1 登记的状态信号
|
||||
// —— 扩大它意味着要同时改设计、帧门和这张表。
|
||||
func TestFrameScopeAllowsExactlyTheStateSignals(t *testing.T) {
|
||||
t.Parallel()
|
||||
if frameReachesAll("frame_type_nobody_classified") {
|
||||
@@ -250,8 +244,7 @@ func TestFrameScopeAllowsExactlyTheStateSignals(t *testing.T) {
|
||||
assertFrameTypes(t, "design/11 §7.1 whitelist", public, want)
|
||||
}
|
||||
|
||||
// frameTypes returns the table's frame types in table order (all of them, or only
|
||||
// the public ones).
|
||||
// frameTypes 按表顺序返回表中的帧类型(全部,或仅公开的那些)。
|
||||
func frameTypes(cases []frameScopeCase, publicOnly bool) []string {
|
||||
out := make([]string, 0, len(cases))
|
||||
for _, tc := range cases {
|
||||
@@ -263,10 +256,10 @@ func frameTypes(cases []frameScopeCase, publicOnly bool) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// publishFrameScopeCases publishes every row on its production subject, followed by
|
||||
// the sentinel that closes the batch. The batch is paced: a client whose send buffer
|
||||
// is full has its frames dropped (the hub's documented slow-client policy), so a
|
||||
// 37-frame burst would exercise the drop policy rather than the gate.
|
||||
// publishFrameScopeCases 在每行各自的生产主题上发布它,随后发布关闭
|
||||
// 批次的哨兵。批次是节流的:发送缓冲已满的客户端其帧会被丢弃
|
||||
// (hub 有文档的慢客户端策略),因此 37 帧的突发放送会去考验丢弃
|
||||
// 策略而不是帧门。
|
||||
func publishFrameScopeCases(t *testing.T, env *testEnv, cases []frameScopeCase) {
|
||||
t.Helper()
|
||||
for i, tc := range cases {
|
||||
@@ -282,9 +275,9 @@ func publishFrameScopeCases(t *testing.T, env *testEnv, cases []frameScopeCase)
|
||||
}
|
||||
}
|
||||
|
||||
// readFrameTypes reads exactly want frames and returns their types in arrival order.
|
||||
// It reports an error rather than failing the test so it can run on the reader
|
||||
// goroutines that drain each client while the batch is published.
|
||||
// readFrameTypes 恰好读取 want 个帧并按到达顺序返回其类型。它返回错误
|
||||
// 而不是让测试失败,以便能跑在批次发布期间排空各客户端的读取
|
||||
// goroutine 上。
|
||||
func readFrameTypes(conn *websocket.Conn, want int) ([]string, error) {
|
||||
got := make([]string, 0, want)
|
||||
for len(got) < want {
|
||||
@@ -302,7 +295,7 @@ func readFrameTypes(conn *websocket.Conn, want int) ([]string, error) {
|
||||
return got, nil
|
||||
}
|
||||
|
||||
// assertFrameTypes compares the received frame types to the expected sequence.
|
||||
// assertFrameTypes 比较收到的帧类型与期望序列。
|
||||
func assertFrameTypes(t *testing.T, what string, got, want []string) {
|
||||
t.Helper()
|
||||
if len(got) != len(want) {
|
||||
@@ -315,7 +308,7 @@ func assertFrameTypes(t *testing.T, what string, got, want []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// containsFrameType reports whether typ is among the received frame types.
|
||||
// containsFrameType 报告 typ 是否在收到的帧类型之中。
|
||||
func containsFrameType(types []string, typ string) bool {
|
||||
for _, got := range types {
|
||||
if got == typ {
|
||||
|
||||
Reference in new issue
Block a user