#974 微信Bot sendtyping彻底修复
CI / gate (push) Has been cancelled

根因: sendtyping三个bug - 1.ilink_user_id误用bot ID(应from_user_id用户ID) 2.请求缺base_info 3.未检查ret==0。另发现账号session已过期(-14 session timeout)是sendtyping失效+文本失败的根源。修复: getconfig/sendtyping补base_info+正确ilink_user_id+ret==0判断, -14时写session_expired日志。
This commit is contained in:
qihu-bot committed 2026-08-18 11:30:15 +08:00
1 parent 9cf4378bf5
commit f975672b0e
1 file changed
+32 -8
+32 -8
View File
@@ -319,7 +319,11 @@ def _wechat_send_message(baseurl: str, bot_token: str, to_user_id: str, context_
def _wechat_get_typing_ticket(baseurl: str, bot_token: str, ilink_user_id: str, context_token: str) -> str: def _wechat_get_typing_ticket(baseurl: str, bot_token: str, ilink_user_id: str, context_token: str) -> str:
"""getconfig 获取 typing_ticket(按 ilink_user_id 缓存 24h)。""" """getconfig 获取 typing_ticket(按 ilink_user_id 缓存 24h)。
#974 修复:ilink_user_id 必须传【用户 ID】(from_user_id),不是 bot ID;
请求体必须带 base_info;响应必须 ret==0 才算成功。
"""
global _typing_ticket_cache global _typing_ticket_cache
_now = time.time() _now = time.time()
_hit = _typing_ticket_cache.get(ilink_user_id) _hit = _typing_ticket_cache.get(ilink_user_id)
@@ -329,14 +333,30 @@ def _wechat_get_typing_ticket(baseurl: str, bot_token: str, ilink_user_id: str,
resp = requests.post( resp = requests.post(
baseurl.rstrip("/") + "/ilink/bot/getconfig", baseurl.rstrip("/") + "/ilink/bot/getconfig",
headers=_wechat_headers(bot_token), headers=_wechat_headers(bot_token),
json={"ilink_user_id": ilink_user_id, "context_token": context_token}, json={
"ilink_user_id": ilink_user_id,
"context_token": context_token,
"base_info": {"channel_version": "1.0.3"},
},
timeout=10, timeout=10,
) )
body = resp.json() if resp.content else {} body = resp.json() if resp.content else {}
# ret==0 才算成功;-14 会话过期 / -4 RPC 失败均无 ticket
ret = body.get("ret")
errcode = body.get("errcode")
if ret == 0 or (ret is None and errcode is None):
ticket = body.get("typing_ticket", "") if isinstance(body, dict) else "" ticket = body.get("typing_ticket", "") if isinstance(body, dict) else ""
if ticket: if ticket:
_typing_ticket_cache[ilink_user_id] = (ticket, _now) _typing_ticket_cache[ilink_user_id] = (ticket, _now)
return ticket return ticket
# 会话过期:记录,供上层标记 expired
if errcode == -14 or ret == -14:
try:
with open("/tmp/wechat_session_expired.log", "a", encoding="utf-8") as _f:
_f.write(_beijing_now().isoformat() + " GETCONFIG_SESSION_EXPIRED user=%s\n" % ilink_user_id)
except Exception:
pass
return ""
except Exception: except Exception:
return "" return ""
@@ -349,7 +369,12 @@ def _wechat_send_typing(baseurl: str, bot_token: str, ilink_user_id: str, typing
resp = requests.post( resp = requests.post(
baseurl.rstrip("/") + "/ilink/bot/sendtyping", baseurl.rstrip("/") + "/ilink/bot/sendtyping",
headers=_wechat_headers(bot_token), headers=_wechat_headers(bot_token),
json={"ilink_user_id": ilink_user_id, "typing_ticket": typing_ticket, "status": status}, json={
"ilink_user_id": ilink_user_id,
"typing_ticket": typing_ticket,
"status": status,
"base_info": {"channel_version": "1.0.3"},
},
timeout=10, timeout=10,
) )
return resp.ok return resp.ok
@@ -633,12 +658,11 @@ def _wechat_receiver_loop(account_id: int):
+ " ctx=" + repr(ctx) + " raw=" + json.dumps(m, ensure_ascii=False) + "\n") + " ctx=" + repr(ctx) + " raw=" + json.dumps(m, ensure_ascii=False) + "\n")
except Exception: except Exception:
pass pass
# 发送"正在输入"状态(尽力而为,失败静默) # 发送"正在输入"状态(#974:ilink_user_id 用用户 ID = sender,非 bot ID)
try: try:
_bot_id = m.get("to_user_id") or d.get("ilink_bot_id") or "" _ticket = _wechat_get_typing_ticket(baseurl, bot_token, sender, ctx)
_ticket = _wechat_get_typing_ticket(baseurl, bot_token, _bot_id, ctx) if sender and _ticket:
if _bot_id and _ticket: _wechat_send_typing(baseurl, bot_token, sender, _ticket, 1)
_wechat_send_typing(baseurl, bot_token, _bot_id, _ticket, 1)
except Exception: except Exception:
pass pass
# 先生成回复(此时历史尚未包含本条,避免重复) # 先生成回复(此时历史尚未包含本条,避免重复)