Files
Cyrene_v2/internal/services/gateway/ws_history.go
T
AskaEth 355f81d04a
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(gateway): gateway 第 2 批 5 个文件注释改中文(只改注释,代码零字节改动)
主人 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 的测试名与断言字面量一字符未改。
2026-10-03 22:10:33 +08:00

49 lines
1.9 KiB
Go
Raw 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 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}})
}