fix(gateway): directMsgPerMin 的写入路径 5 处透传(关掉「面板保存把 -1 静默重置为 0」)
- 缺口:后端解析与面板都已就绪,但 gateway 没让该字段通过 ⇒ 面板保存一次渠道配置就把主人手配的「关闭流控(-1)」重置为 0=保护性默认 6 条/分 - 5 处:AdminChannelAccount DTO / channelConfigRequest / config.ChannelAccount 拷贝 / adminChannelAccountOf 映射 / 微信扫码重建账号 - 语义零改动(只透传);变异实测:删拷贝 ⇒ channels.json 变 0(want -1)、删微信重建拷贝 ⇒ 同红、删 GET 映射 ⇒ 回显缺失 - 顺带登记一条负载诱发 flake(capability/plugin 的 TestManagerInstall_ConnectFailureDoesNotPersist,靠「端口被拒」断言,满载时端口被抢)⇒ 非本切片引入,已进 00-索引 §四
This commit is contained in:
1 parent
321cc3b763
commit
7aaf7731dc
3 files changed
+208
-30
No files matched your search
@@ -41,6 +41,13 @@ type AdminChannelAccount struct {
|
||||
GroupMsgPerMin int `json:"groupMsgPerMin,omitempty"`
|
||||
MsgPerMin int `json:"msgPerMin,omitempty"`
|
||||
MaxMessages int `json:"maxMessages,omitempty"`
|
||||
// DirectMsgPerMin 是**非主人私聊(陌生人)每分钟每发送者上限**
|
||||
// (design/12 §6 策略三;主人 2026-10-05 裁决③与裁决 13)。它是账号
|
||||
// **顶层**字段(与 GroupMsgPerMin 同一条写路径,**不在 config 里**),
|
||||
// 语义与 `channelbridge.directLimit` 逐字同口径:0 或未设置为保护性
|
||||
// 默认 6 条/分、正值固定为该值、**负值 = 关闭该限制**。面板必须能把它
|
||||
// 原样回显,否则「已关闭」会被静默显示成「未设置」。
|
||||
DirectMsgPerMin int `json:"directMsgPerMin,omitempty"`
|
||||
// PersonaID 是该账号应答所用的角色(design/22 §2 方案 b),账号
|
||||
// 未绑定任何角色时省略。它是人格 id,不是秘密。
|
||||
PersonaID string `json:"personaId,omitempty"`
|
||||
@@ -101,6 +108,12 @@ type channelConfigRequest struct {
|
||||
GroupMsgPerMin int `json:"groupMsgPerMin"`
|
||||
MsgPerMin int `json:"msgPerMin"`
|
||||
MaxMessages int `json:"maxMessages"`
|
||||
// DirectMsgPerMin 是账号顶层的陌生人私聊每分钟每发送者上限,与
|
||||
// GroupMsgPerMin 同一口径的**值语义**(对非 config 字段是整值替换):
|
||||
// 缺失或 0 → 保护性默认 6 条/分,正值 → 该值,**负值 = 关闭该限制**。
|
||||
// 它必须原样落到 config.ChannelAccount,绝不能被吞成 0 —— 否则主人显式
|
||||
// 关掉的限制会被一次面板保存静默重置回默认 6(见 adminSaveChannelConfig)。
|
||||
DirectMsgPerMin int `json:"directMsgPerMin"`
|
||||
// PersonaID 是该账号应答所用的角色(design/22 §2 方案 b)。它是
|
||||
// 指针,因为线上契约是三态的,而普通 string 无法
|
||||
// 区分键缺失与显式 "":缺失保留已存绑定,
|
||||
@@ -160,17 +173,20 @@ func (s *Server) adminSaveChannelConfig(w http.ResponseWriter, r *http.Request)
|
||||
accounts := s.channels.Load()
|
||||
// patch 语义:未在 cfg 里出现的 config 键保留盘上已存值;cfg 里显式为
|
||||
// null/"" 的键被清除。非 config 字段(黑白名单 / 限流 / personaId)仍是整值替换。
|
||||
// DirectMsgPerMin 必须**逐字**落到账号上:它就是面板「关闭流控(-1)」的
|
||||
// 保存路径,吞成 0 等于把主人显式关掉的限制静默重置回保护性默认 6 条/分。
|
||||
updated := runtimeconfig.PatchChannel(accounts, platform, config.ChannelAccount{
|
||||
ID: strings.TrimSpace(req.ID),
|
||||
Config: cfg,
|
||||
AllowGroups: req.AllowGroups,
|
||||
DenyGroups: req.DenyGroups,
|
||||
AllowUsers: req.AllowUsers,
|
||||
DenyUsers: req.DenyUsers,
|
||||
GroupMsgPerMin: req.GroupMsgPerMin,
|
||||
MsgPerMin: req.MsgPerMin,
|
||||
MaxMessages: req.MaxMessages,
|
||||
PersonaID: channelPersonaBinding(req.PersonaID, existingChannelAccount(accounts[platform], req.ID)),
|
||||
ID: strings.TrimSpace(req.ID),
|
||||
Config: cfg,
|
||||
AllowGroups: req.AllowGroups,
|
||||
DenyGroups: req.DenyGroups,
|
||||
AllowUsers: req.AllowUsers,
|
||||
DenyUsers: req.DenyUsers,
|
||||
GroupMsgPerMin: req.GroupMsgPerMin,
|
||||
MsgPerMin: req.MsgPerMin,
|
||||
MaxMessages: req.MaxMessages,
|
||||
DirectMsgPerMin: req.DirectMsgPerMin,
|
||||
PersonaID: channelPersonaBinding(req.PersonaID, existingChannelAccount(accounts[platform], req.ID)),
|
||||
})
|
||||
if err := runtimeconfig.SaveChannels(s.channels.Path(), updated); err != nil {
|
||||
s.auditClaims(r, "channel.save", "error")
|
||||
@@ -413,16 +429,17 @@ func savedAccountID(list []config.ChannelAccount, supplied string) string {
|
||||
// adminChannelAccountOf 把一个(已脱敏的)账号映射为其管理侧线上结构。
|
||||
func adminChannelAccountOf(acct config.ChannelAccount) AdminChannelAccount {
|
||||
return AdminChannelAccount{
|
||||
ID: acct.ID,
|
||||
Config: acct.Config,
|
||||
AllowGroups: acct.AllowGroups,
|
||||
DenyGroups: acct.DenyGroups,
|
||||
AllowUsers: acct.AllowUsers,
|
||||
DenyUsers: acct.DenyUsers,
|
||||
GroupMsgPerMin: acct.GroupMsgPerMin,
|
||||
MsgPerMin: acct.MsgPerMin,
|
||||
MaxMessages: acct.MaxMessages,
|
||||
PersonaID: acct.PersonaID,
|
||||
ID: acct.ID,
|
||||
Config: acct.Config,
|
||||
AllowGroups: acct.AllowGroups,
|
||||
DenyGroups: acct.DenyGroups,
|
||||
AllowUsers: acct.AllowUsers,
|
||||
DenyUsers: acct.DenyUsers,
|
||||
GroupMsgPerMin: acct.GroupMsgPerMin,
|
||||
MsgPerMin: acct.MsgPerMin,
|
||||
MaxMessages: acct.MaxMessages,
|
||||
DirectMsgPerMin: acct.DirectMsgPerMin,
|
||||
PersonaID: acct.PersonaID,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user