docs(gateway): gateway 剩余文件注释改中文(逐行 1:1,代码零字节改动)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批:
已推库 16 个文件 + 本批剩余文件)。
校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0);
全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
This commit is contained in:
AskaEth committed 2026-10-03 22:28:25 +08:00
1 parent 91e8d7a029
commit 074ffc4ebf
73 files changed
+2529 -2529

No files matched your search

@@ -16,25 +16,25 @@ import (
"git.yeij.top/AskaEth/Cyrene_v2/internal/config/runtimeconfig"
)
// This file covers the admin half of the channel-level role binding (design/22 §2
// 方案 b / §4.4): PUT /admin/channels/{platform}/config accepts personaId through the
// existing read-modify-write + bridge.Reload path, an unknown role is refused
// instead of binding a role that cannot answer, and the list endpoint reports the
// binding back.
// 本文件覆盖渠道级角色绑定的管理侧一半(design/22 §2
// 方案 b / §4.4):PUT /admin/channels/{platform}/config 通过
// 既有的 read-modify-write + bridge.Reload 路径接受 personaId,
// 未知角色会被拒绝,而不是绑定一个无法应答的角色;
// 列表端点会回报该绑定。
//
// personaId is three-state on the wire, because the panel sends the key only when
// the owner actually touched the role select:
// personaId 在线上是三态的,因为面板仅在主人
// 真正触碰过角色选择时才发送该键:
//
// key absent → keep the stored binding
// explicit "" → clear the binding
// non-empty id → bind that role (unknown id → 400)
// 键缺失 → 保留已存绑定
// 显式 "" → 清除绑定
// 非空 id → 绑定该角色(未知 id → 400)
//
// The absent-key case is the one that silently dropped bindings, so it is asserted
// with a literal JSON body: a map[string]any would still make the assertion pass if
// the DTO had picked up a value from somewhere else.
// 「键缺失」这一情形正是静默丢弃绑定的那个,因此用字面量
// JSON 请求体断言:若 DTO 从别处取到了值,map[string]any
// 仍会让断言通过。
// putChannelConfigRaw posts a literal JSON body so a test can pin the exact wire
// shape (notably: no personaId key at all).
// putChannelConfigRaw 发送字面量 JSON 请求体,使测试能钉死确切的
// 线上结构(尤其是:完全没有 personaId 键)。
func putChannelConfigRaw(t *testing.T, ts *httptest.Server, platform, raw, token string) (*http.Response, []byte) {
t.Helper()
req, err := http.NewRequest(http.MethodPut,
@@ -59,7 +59,7 @@ func putChannelConfigRaw(t *testing.T, ts *httptest.Server, platform, raw, token
return resp, b
}
// storedPersonaID reads the binding channels.json holds for one account.
// storedPersonaID 读取 channels.json 为某个账号保存的绑定。
func storedPersonaID(t *testing.T, path, platform, accountID string) string {
t.Helper()
accounts, warn := runtimeconfig.LoadChannels(path, nil)
@@ -75,8 +75,8 @@ func storedPersonaID(t *testing.T, path, platform, accountID string) string {
return ""
}
// listedPersonaID is the personaId GET /admin/channels reports for one account, i.e.
// what the panel reads back to render the role select.
// listedPersonaID 是 GET /admin/channels 为某个账号报告的 personaId,
// 即面板读回用于渲染角色选择的值。
func listedPersonaID(t *testing.T, ts *httptest.Server, token, platform, accountID string) (string, []byte) {
t.Helper()
resp, body := doReq(t, http.MethodGet, ts.URL+"/api/v1/admin/channels", nil, token)
@@ -107,9 +107,9 @@ func listedPersonaID(t *testing.T, ts *httptest.Server, token, platform, account
return "", body
}
// TestAdminSaveChannelConfigPersonaIDBindsAndEchoes binds a channel role and
// asserts it reached channels.json, that the list endpoint echoes it back for the
// panel to render, and that the hot-reload path ran.
// TestAdminSaveChannelConfigPersonaIDBindsAndEchoes 绑定一个渠道角色,
// 断言它到达了 channels.json、列表端点回显它供面板渲染,
// 并且热重载路径被执行。
func TestAdminSaveChannelConfigPersonaIDBindsAndEchoes(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "channels.json")
@@ -136,9 +136,9 @@ func TestAdminSaveChannelConfigPersonaIDBindsAndEchoes(t *testing.T) {
t.Logf("GET /api/v1/admin/channels echoes the binding: %s", listBody)
}
// TestAdminSaveChannelConfigPersonaIDKeptWhenOmitted is the regression for the
// silent data loss: the panel omits personaId unless the owner touched the role
// select, so saving another field must leave the stored binding alone.
// TestAdminSaveChannelConfigPersonaIDKeptWhenOmitted 是静默数据
// 丢失的回归:除非主人触碰过角色选择,面板会省略 personaId,
// 因此保存另一个字段必须不碰已存绑定。
func TestAdminSaveChannelConfigPersonaIDKeptWhenOmitted(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "channels.json")
@@ -148,8 +148,8 @@ func TestAdminSaveChannelConfigPersonaIDKeptWhenOmitted(t *testing.T) {
_, ts, jwt := buildEnv(t, cfgDefault(), Deps{Channels: store, Personas: personaTestRegistry(t)})
tok := signAny(t, jwt, "acct", auth.RoleOwner)
// The wire body carries the new token and no personaId key at all — exactly
// what an untouched role select produces.
// 线上请求体携带新 token,且完全没有 personaId 键 ——
// 正是一个未被触碰的角色选择所产生的形态。
_, body := putChannelConfigRaw(t, ts,
"telegram", `{"id":"conf0","token":"new-tok","groupMsgPerMin":5}`, tok)
@@ -164,16 +164,16 @@ func TestAdminSaveChannelConfigPersonaIDKeptWhenOmitted(t *testing.T) {
t.Fatalf("GET /admin/channels personaId = %q, want yuki (body=%s)", echoed, listBody)
}
// An explicit JSON null is the same as an absent key: the DTO cannot tell them
// apart, and neither means "clear".
// 显式的 JSON null 与键缺失相同:DTO 无法区分二者,
// 二者都不表示「清除」。
putChannelConfigRaw(t, ts, "telegram", `{"id":"conf0","token":"newer-tok","personaId":null}`, tok)
if got := storedPersonaID(t, path, "telegram", "conf0"); got != "yuki" {
t.Fatalf("null personaId cleared the binding: personaId = %q, want yuki", got)
}
}
// TestAdminSaveChannelConfigPersonaIDClearedOnExplicitEmpty asserts that clearing
// the binding still works, but only when the panel says so with an explicit "".
// TestAdminSaveChannelConfigPersonaIDClearedOnExplicitEmpty 断言清除
// 绑定仍然可行,但仅在面板以显式 "" 表示时才如此。
func TestAdminSaveChannelConfigPersonaIDClearedOnExplicitEmpty(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "channels.json")
@@ -193,9 +193,9 @@ func TestAdminSaveChannelConfigPersonaIDClearedOnExplicitEmpty(t *testing.T) {
}
}
// TestAdminSaveChannelConfigPersonaIDKeptPerAccount pins the read-modify-write to
// the account being saved: an omitted personaId on one account must inherit that
// account's binding, not a sibling's.
// TestAdminSaveChannelConfigPersonaIDKeptPerAccount 把 read-modify-write
// 钉在正在保存的账号上:某账号省略 personaId 时必须继承该
// 账号自己的绑定,而不是兄弟账号的。
func TestAdminSaveChannelConfigPersonaIDKeptPerAccount(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "channels.json")
@@ -218,9 +218,9 @@ func TestAdminSaveChannelConfigPersonaIDKeptPerAccount(t *testing.T) {
}
}
// TestAdminSaveChannelConfigRejectsUnknownPersonaID keeps the save fail-closed: a
// channel bound to a role the library does not know would silently answer as the
// default role, so it is refused and nothing is written or reloaded.
// TestAdminSaveChannelConfigRejectsUnknownPersonaID 保持保存 fail-closed:
// 绑定到一个库不认识的角色时,渠道会静默地以默认角色应答,
// 因此该绑定被拒绝,不写入也不重载。
func TestAdminSaveChannelConfigRejectsUnknownPersonaID(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "channels.json")