refactor(weixin-ilink): 措辞纠正 —「会话过期」→「会话被 iLink 拒绝」(零逻辑改动)
事实(主人 2026-10-03 确认):iLink 的 bot token 是长期凭据(一个月前扫码的仍可用);errcode=-14 是 iLink 侧拒绝/作废该会话,不是时间性过期;且至今未观测到真实 -14(当日全部日志 0 次)。此前代码把这些写成「过期」,属沿用的旧命名,现纠正。 - 纯改名/文案:ErrSessionExpired→ErrSessionRejected、errSessionExpired→errcodeSessionRejected、expired/expiredToken→rejected/rejectedToken、markExpired/expiredLocked/expiredState→markRejected/rejectedLocked/rejectedState;409 错误码 session_expired→session_rejected - 行为一字未改:显式标记 / Connect 不假 OK / 面板 needsRescan+lastError / 扫码或换新 token 即清除 全部保留 - 微信协议自身的「二维码过期」与 auth 的 JWT/refresh 过期一律未动(那些是真·时间性过期) - Docs/api-client v0.39 补事实说明;顺手收尾 3 处残留注释(admin.go / channelbridge/inbound.go / readloop_test.go)
This commit is contained in:
1 parent
cdc370dc82
commit
a51aadeef4
14 files changed
+205
-192
No files matched your search
@@ -63,8 +63,12 @@ const (
|
||||
// ilinkVersion mirrors the upstream @tencent-weixin/openclaw-weixin version
|
||||
// whose client version we advertise on the wire as iLink-App-ClientVersion.
|
||||
ilinkVersion = "2.4.8"
|
||||
// errSessionExpired is the iLink errcode for an expired bot token.
|
||||
errSessionExpired = -14
|
||||
// errcodeSessionRejected is the iLink errcode meaning iLink rejected or
|
||||
// invalidated this session credential. It is NOT a time-based expiry: the bot
|
||||
// token is a long-lived credential (a token obtained by scanning a month ago
|
||||
// still works), so -14 means iLink no longer accepts this session — unbound,
|
||||
// re-logged-in elsewhere, or refused at the protocol level.
|
||||
errcodeSessionRejected = -14
|
||||
)
|
||||
|
||||
// Sentinel errors returned by this adapter, usable with errors.Is.
|
||||
@@ -73,8 +77,8 @@ var (
|
||||
ErrInvalidConfig = errors.New("weixin_ilink: invalid config")
|
||||
// ErrLoginTimeout is returned when the QR code is not confirmed in time.
|
||||
ErrLoginTimeout = errors.New("weixin_ilink: qr login timed out")
|
||||
// ErrSessionExpired is returned when iLink reports errcode=-14.
|
||||
ErrSessionExpired = errors.New("weixin_ilink: session expired, re-scan required")
|
||||
// ErrSessionRejected is returned when iLink reports errcode=-14.
|
||||
ErrSessionRejected = errors.New("weixin_ilink: iLink rejected the session (errcode=-14); re-scan required")
|
||||
// ErrNeedsLogin is returned by Connect when no bot_token is configured yet; the
|
||||
// scan-code bind must be driven via the panel login-qr/login-status endpoints.
|
||||
ErrNeedsLogin = errors.New("weixin_ilink: bot not logged in yet, scan the QR")
|
||||
@@ -159,15 +163,15 @@ type Adapter struct {
|
||||
|
||||
mu sync.RWMutex
|
||||
connected bool
|
||||
// expired marks a session iLink rejected with errcode=-14: the bot token is
|
||||
// dead and only a fresh scan-code login re-binds it (session_state.go).
|
||||
// expiredToken records WHICH token was rejected, so a subsequently configured
|
||||
// rejected marks a session iLink rejected with errcode=-14: the credential is
|
||||
// refused until a fresh scan-code login re-binds it (session_state.go).
|
||||
// rejectedToken records WHICH token was rejected, so a subsequently configured
|
||||
// token clears the state; rescanDetail is the panel-visible reason. All three
|
||||
// are guarded by mu.
|
||||
expired bool
|
||||
expiredToken string
|
||||
rescanDetail string
|
||||
qrcode string
|
||||
rejected bool
|
||||
rejectedToken string
|
||||
rescanDetail string
|
||||
qrcode string
|
||||
// pollBaseURL optionally overrides cfg.BaseURL for get_qrcode_status polling.
|
||||
// It is set when the server returns scaned_but_redirect with a redirect_host,
|
||||
// so subsequent status polls follow the IDC host. Guarded by mu.
|
||||
@@ -242,14 +246,14 @@ func (a *Adapter) Config() map[string]any {
|
||||
// runs the scan-code login flow (see login.go).
|
||||
//
|
||||
// A token iLink already rejected with errcode=-14 is NOT usable: Connect refuses
|
||||
// it with ErrSessionExpired (re-scan required) instead of reporting a session
|
||||
// it with ErrSessionRejected (re-scan required) instead of reporting a session
|
||||
// that the very next poll would tear down, and the scan-code login flow is the
|
||||
// way back (see login_admin.go StartLogin).
|
||||
func (a *Adapter) Connect(ctx context.Context) error {
|
||||
if expired, reason := a.expiredState(); expired {
|
||||
a.log.Error("ilink connect refused: session expired, 需要重新扫码登录",
|
||||
if rejected, reason := a.rejectedState(); rejected {
|
||||
a.log.Error("ilink connect refused: session rejected, 需要重新扫码绑定(请用「扫码登录」)",
|
||||
"bot_id", a.botID(), "reason", reason)
|
||||
return fmt.Errorf("%w: %s", ErrSessionExpired, reason)
|
||||
return fmt.Errorf("%w: %s", ErrSessionRejected, reason)
|
||||
}
|
||||
a.mu.RLock()
|
||||
connected := a.connected
|
||||
@@ -300,14 +304,14 @@ func (a *Adapter) IsConnected() bool {
|
||||
}
|
||||
|
||||
// HealthCheck verifies the session is usable: it must be connected and carry a
|
||||
// bot_token. An expired session (iLink rejected the token with errcode=-14) is
|
||||
// reported as ErrSessionExpired — "re-scan required" — so a caller can tell a
|
||||
// dead credential apart from a plain disconnected adapter. It does not probe the
|
||||
// bot_token. A session iLink rejected (errcode=-14) is reported as
|
||||
// ErrSessionRejected — "re-scan required" — so a caller can tell a refused
|
||||
// credential apart from a plain disconnected adapter. It does not probe the
|
||||
// network so callers can use it cheaply after a reconnect without incurring a
|
||||
// request.
|
||||
func (a *Adapter) HealthCheck(ctx context.Context) error {
|
||||
if expired, reason := a.expiredState(); expired {
|
||||
return fmt.Errorf("%w: %s", ErrSessionExpired, reason)
|
||||
if rejected, reason := a.rejectedState(); rejected {
|
||||
return fmt.Errorf("%w: %s", ErrSessionRejected, reason)
|
||||
}
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
|
||||
Reference in new issue
Block a user