From bfbf5057bc0a63dc4c2a41a687f1c38972772441 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 26 Oct 2026 19:48:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor(weixin):=20runLogin=20=E7=9A=84?= =?UTF-8?q?=E5=AE=88=E5=8D=AB=E8=AF=B4=E6=98=8E=E4=B8=8A=E7=A7=BB=E5=88=B0?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=A4=B4=EF=BC=8C=E5=9B=9E=E5=88=B0=2080=20?= =?UTF-8?q?=E8=A1=8C=E4=BB=A5=E5=86=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 复审 r2:runLogin 70 → 82 行越过 AGENTS.md §10 的函数 ≤80 上限。代码行本来 只有 56,超的是 M50 加在循环体内的两段 🔴 说明。把 status/redirect_host 的 出镜口径整段上移到函数头注释(不参与计数),循环体内只留一行指向函数头; **控制流与守卫代码零改动**。 改后 runLogin = 76 行(全 plugins/channels 最长 79,其余均 ≤80)。 --- plugins/channels/weixin_ilink/login.go | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/plugins/channels/weixin_ilink/login.go b/plugins/channels/weixin_ilink/login.go index 04372a0..3971527 100644 --- a/plugins/channels/weixin_ilink/login.go +++ b/plugins/channels/weixin_ilink/login.go @@ -67,6 +67,19 @@ func (a *Adapter) login(ctx context.Context) error { // runLogin 轮询 get_qrcode_status,直到二维码被确认或登录窗口结束,然后把结果记录在 // 会话上。它运行在 goroutine 中,所以 StartLogin 能立即返回,而面板轮询 LoginStatus。 +// +// 🔴 出镜口径(M50):`status` 与 `redirect_host` 都是**上游字段**,进日志前一律过 +// trace.ErrorToken(协议枚举字段的那道守卫,判据见 internal/runtime/trace/errortoken.go): +// 真实取值(wait / scaned / confirmed / scaned_but_redirect / idc.weixin.qq.com …)原样 +// 通过;上游若在枚举位上塞散文,那一栏整体变空串。 +// +// 🔴 **控制流只用原值**:setPhase、下面的 switch、setPollBaseURL 与 confirmingPhase 读 +// 的都是原始串 —— 渲染口径绝不参与判定。一个图省事的修法是把守卫后的值喂给 +// setPollBaseURL,那会让带端口的合法重定向主机整体失效(用例 +// TestStartLogin_ProseRedirectHostNeverReachesLog 钉的就是这个方向)。 +// +// 同一个 status 还有第二个日志出口(复用二维码时那条 INFO 打 currentPhase),在 +// login_admin.go 里过同一道守卫。 func (a *Adapter) runLogin(sess *loginSession, sessCtx context.Context) { timeoutCtx, cancel := context.WithTimeout(sessCtx, a.cfg.LoginTimeout) defer cancel() @@ -86,15 +99,7 @@ func (a *Adapter) runLogin(sess *loginSession, sessCtx context.Context) { } return } - // 跟踪线上的原始阶段,便于 StartLogin 保护「已扫描/确认中」的绑定不被重新取码。 - // 仅在状态变化时打日志以避免噪声,且绝不记录 qrcode 标识符或 token。 - // - // 🔴 status 是**上游字段**:进日志前过令牌守卫(trace.ErrorToken)。真实取值 - // (wait / scaned / confirmed / scaned_but_redirect / …)全是短令牌 ⇒ 原样通过; - // 上游若在这一栏塞散文,这一行就是空串 —— 与 qq_obv11 的 status、 - // trace.UpstreamError 的 code/type 同一道守卫(M50 复审的第五个出口)。 - // **控制流仍用原值**:setPhase 与下面的 switch 都读 status.Status,渲染口径 - // 不参与判定。 + // status 进日志前过令牌守卫(口径见函数头);控制流仍用原值。 sess.setPhase(status.Status) if status.Status != prevStatus { prevStatus = status.Status @@ -124,10 +129,7 @@ func (a *Adapter) runLogin(sess *loginSession, sessCtx context.Context) { a.setLoginState(LoginStatusWaiting, loginScannedDetail) case "scaned_but_redirect": if status.RedirectHost != "" { - // 🔴 路由用**原值**(下一行),日志只留守卫后的形态:redirect_host 是上游 - // 字段,与上面的 status 同一道令牌守卫(trace.ErrorToken)。真实主机名通过; - // 带端口(`h:8443`)或散文的整体丢弃 —— 宁可日志少一个字段,也不让这一栏 - // 成为第二个正文通道。 + // 路由用**原值**,日志只留守卫后的形态(口径见函数头)。 a.setPollBaseURL(status.RedirectHost) a.log.Info("weixin_ilink: idc redirect, switching polling host", "host", trace.ErrorToken(status.RedirectHost))