主人 2026-10-03 拍板「注释一律中文」。本批 = WS 上行门与握手回放那批文件: ws_hub.go / ws_history.go / ws_route.go / ws_role_gate_test.go / voice_signal_test.go 含中文的整行注释 6 → 148;无行尾注释。 校验(判据 = "只改注释、零代码字节改动"): - git diff -U0 | 排除 +++/--- / 注释行 / 空行 / 行尾注释 → 为空 (含"把纯空行变动也视为违规"的更严变体,同样为空) - 独立实现:两侧剥掉注释后逐行比对代码文本 → 5/5 全等 - gofmt -l 干净(改动前同样干净,不存在"顺手格式化") - go test ./... 全绿;go build/vet 绿;linux/amd64 + darwin/arm64 交叉编译绿 安全约束强度逐句保留:ws_route.go 的「默认拒(非黑名单)/ 删掉它等于放开一切」、 ws_history.go 的「门在 replayHistory 第一条语句 / 扩角色须先登记 design/11 §7.2 / 回放不含 thinking」、ws_role_gate_test.go 的测试名与断言字面量一字符未改。
49 lines
1.9 KiB
Go
49 lines
1.9 KiB
Go
package gateway
|
||
|
||
import (
|
||
"context"
|
||
)
|
||
|
||
// wsReplayLimit 是回放给新接入客户端的最近消息条数。刻意取小值,使重连代价
|
||
// 低廉;完整活跃会话历史由前端走 REST 拉取(design/16 §4.1),回放只是让
|
||
// 一条全新连接立刻拿到上下文。
|
||
const wsReplayLimit = 50
|
||
|
||
// replayHistory 把 sessionID 最近的若干条消息作为 ws "history" 事件发给
|
||
// 单条刚注册的连接。
|
||
//
|
||
// 回放携带主会话的消息正文,因此仅限 owner/admin(design/11 §7.2 A,主人于
|
||
// 2026-10-03 决策)。ownerAdminClaims 与主动推送用的是同一判据,所以
|
||
// 「谁可以在未被要求的情况下拿到主人的对话」只在一处回答,而不散落到各调用点。
|
||
// viewer 连接完成握手时完全不做回放:它的只读窗口是 REST 监控面
|
||
// (design/11 §7.1「语义澄清」),不是推送。
|
||
//
|
||
// 门放在这里而不是 ws_hub_conn.go 里的 register/回放调用点,是刻意的:
|
||
// 这是唯一发出回放的函数,此后任何调用者都无法绕开该检查。日后主人想让某个
|
||
// 角色也收到回放,必须先把它登记到 design/11 §7.2,与上行帧的做法完全一致
|
||
// (见 ws_route.go)。
|
||
//
|
||
// 回放是尽力而为:store 为 nil 或读取出错都静默跳过。
|
||
// 回放不含 thinking(design/16 §6),因此该帧即使对 owner/admin
|
||
// 也不会泄漏思维链。
|
||
func (h *hub) replayHistory(c *wsConn, sessionID string) {
|
||
if !ownerAdminClaims(c.claims) {
|
||
return
|
||
}
|
||
if h.history == nil {
|
||
return
|
||
}
|
||
msgs, err := h.history.Recent(context.Background(), sessionID, wsReplayLimit)
|
||
if err != nil {
|
||
h.log.Warn("history replay", "err", err, "session", sessionID)
|
||
return
|
||
}
|
||
out := make([]historyMessage, 0, len(msgs))
|
||
for _, m := range msgs {
|
||
wire := toHistoryMessage(m)
|
||
wire.Thinking = ""
|
||
out = append(out, wire)
|
||
}
|
||
c.enqueueJSON(wsEvent{Type: "history", SessionID: sessionID, Data: map[string]any{"messages": out}})
|
||
}
|