feat(channels): 流控可配 —— 陌生人私聊额度走账号配置 directMsgPerMin(裁决 13)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 后端:账号顶层 directMsgPerMin(缺失/0 = 保护性默认 6 条/分;正值 = 该值;负值 = 关闭并留带 source 的 WARN)
- 日志如实报出**实际生效**额度(adapter.(*FlowGate).DirectPerMin()),告警文案不再写死 6
- 面板:渠道配置表单加字段(含帮助文案)+ 回显/写回链路(LIMIT_KEYS 四键)+ 账号卡片摘要
- 文案纠错:AdapterConfigSummary 的 msgPerMin 由「私聊每分钟上限」改为「非主人消息每分钟总上限」(原描述是误导),并列补 directMsgPerMin 行
- 变异实测:缺键丢默认 / 负值当 1 条每分 / 前端吞负值 —— 三个都精确打红并还原
- ⚠️ 已知缺口(下一片补,gateway 面):GET/PUT /admin/channels 尚未下发/解码该键 ⇒ 面板暂时回显空、保存会把 -1 重置为 0
This commit is contained in:
AskaEth committed 2026-10-05 13:50:29 +08:00
1 parent ba17820040
commit a057a0f61f
18 files changed
+339 -70

No files matched your search

+6 -5
View File
@@ -177,16 +177,17 @@ func (b *Bridge) shouldRespond(ctx context.Context, msg adapter.UnifiedMessage,
}
// 裁决①(主人 2026-10-05):**陌生人私聊 = 正常聊天** —— 不设安静期、
// 不走「值不值得回」的概率门,直接进入完整回合。唯一的闸门是强制
// 流控:同一发送者每分钟 ≤ FlowDirectDefault 条(AllowDirect 记账)
// 与同时最多 1 个在跑的回合(processFrom 用 AcquireTurn 施加)。
// 不走「值不值得回」的概率门,直接进入完整回合。唯一的闸门是流控:
// 同一发送者每分钟 ≤ 该账号的 directMsgPerMin(未配 = 保护性默认 6,裁决 13
// 让它可配;AllowDirect 记账)与同时最多 1 个在跑的回合
// (processFrom 用 AcquireTurn 施加)。
// 被限流时**不回**:调用方会把它登记进隔离会话,这里留一条带
// source 的可见告警(绝不静默)。
// source 的可见告警(绝不静默),并报出**实际生效**的额度而不是硬编码默认值。
if isStrangerPrivate(sess) {
if g := b.gateFor(a); g != nil && !g.AllowDirect(msg) {
b.log.Warn("stranger private chat rate limited, registered only",
"platform", msg.Platform, "channel", msg.ChannelID, "sender", msg.SenderID,
"limit_per_min", adapter.FlowDirectDefault)
"limit_per_min", g.DirectPerMin())
return false, "stranger private: over the per-sender flow limit"
}
return true, "stranger private chat: normal reply"