From 904c20bb625c7edac4c08dcb3d423435b313c6ff Mon Sep 17 00:00:00 2001 From: liuwei Date: Thu, 7 May 2026 15:52:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3864=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E6=80=81=E8=AF=86=E5=88=AB=E5=B9=B6=E8=A1=A5=E5=BC=BA=E8=B5=84?= =?UTF-8?q?=E6=96=99=E5=90=8C=E6=AD=A5=E7=AD=89=E5=BE=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wechat_ipad/providers/server_864/login.py | 16 +++++ wechat_ipad/providers/server_864/runtime.py | 68 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/wechat_ipad/providers/server_864/login.py b/wechat_ipad/providers/server_864/login.py index 17776e1..ff7edb2 100644 --- a/wechat_ipad/providers/server_864/login.py +++ b/wechat_ipad/providers/server_864/login.py @@ -24,16 +24,32 @@ class LoginMixin(Server864APIClientBase): normalized_login_state = self._normalize_online_text( self._pick_first(payload, "loginState", "LoginState", "status_text", "statusText") ) + raw_login_state = self._pick_first(payload, "loginState", "LoginState") normalized_status = self._normalize_online_text( self._pick_first(payload, "status", "Status", "state_text", "stateText") ) state_value = self._pick_first(payload, "state", "State") login_flag = self._pick_first(payload, "isLogin", "IsLogin", "online", "Online", "isOnline", "IsOnline") + login_err_msg = self._normalize_online_text( + self._pick_first(payload, "loginErrMsg", "LoginErrMsg", "msg", "message") + ) if normalized_login_state in {"online", "已登录", "在线"}: return True + # 864 的 `GetLoginStatus` 在你当前这版 server 里会直接返回 `loginState: 1`: + # 1. 这不是扫码阶段的 `CheckLoginStatus.state`,而是服务端自身维护的登录态枚举; + # 2. 之前这里只识别到了字符串 `"online"`,导致明明已经在线却仍被判成未登录; + # 3. 这里把常见数字态一并纳入在线判定,避免后续资料拉取与前端显示被卡住。 + try: + normalized_login_state_value = int(raw_login_state or 0) + except (TypeError, ValueError): + normalized_login_state_value = 0 + if normalized_login_state_value in {1, 2}: + return True if normalized_status in {"online", "已登录", "在线"}: return True + if "在线状态良好" in login_err_msg or "账号在线" in login_err_msg: + return True if isinstance(login_flag, bool): return login_flag if str(login_flag or "").strip().lower() in {"true", "1", "online"}: diff --git a/wechat_ipad/providers/server_864/runtime.py b/wechat_ipad/providers/server_864/runtime.py index 027cadb..415456f 100644 --- a/wechat_ipad/providers/server_864/runtime.py +++ b/wechat_ipad/providers/server_864/runtime.py @@ -28,6 +28,57 @@ class Server864RuntimeMixin: def is_runtime_running(self) -> bool: return bool(getattr(self, "_runtime_running", False)) + async def _wait_login_identity_ready( + self, + *, + logger, + on_login_qr_update: AsyncCallback | None = None, + uuid: str = "", + url: str = "", + scan_url: str = "", + login_qr_api: str = "new_x", + login_way: str = "mac", + retry_times: int = 12, + retry_interval_seconds: int = 5, + ) -> bool: + """在 864 已判定在线后,继续等待资料接口把账号身份补齐。""" + for attempt in range(1, retry_times + 1): + if await self._refresh_identity_from_profile(logger=logger): + return True + + try: + login_status = await self.get_login_status(auto_login=False) + except Exception as e: + logger.warning(f"server_864 等待账号资料就绪时获取登录状态失败: {e}") + else: + if self._is_online_from_login_status_payload(login_status): + # 服务端已在线但资料还没取到时,前端不应继续停在“未登录”语义: + # 1. 用户当前最困惑的点正是“明明在线了,为什么页面还不显示登录成功”; + # 2. 这类场景更接近“服务端在线,账号资料同步中”,需要一个更准确的中间态提示; + # 3. 因此这里主动把状态更新到“资料同步中”,让首页知道并非扫码失败。 + await self._safe_callback( + on_login_qr_update, + { + "uuid": uuid, + "url": url, + "scan_url": scan_url, + "status": "confirmed", + "status_text": f"864 服务端已在线,正在同步账号资料(第 {attempt}/{retry_times} 次)", + "login_source": "fresh_qr", + "provider_name": "server_864", + "provider_stage": "login_finalizing", + "connection_ready": True, + "login_required": False, + "login_qr_api": login_qr_api, + "login_way": login_way, + }, + logger=logger, + callback_name="on_login_qr_update", + ) + if attempt < retry_times: + await asyncio.sleep(retry_interval_seconds) + return False + @staticmethod def _normalize_login_runtime_message(message: str) -> str: """把 864 登录阶段抛出的原始错误整理成更适合前端展示的短文本。""" @@ -153,7 +204,12 @@ class Server864RuntimeMixin: ) -> None: """确保 864 已完成登录。""" if await self.is_logged_in(): - identity_ready = await self._refresh_identity_from_profile(logger=logger) + identity_ready = await self._wait_login_identity_ready( + logger=logger, + on_login_qr_update=on_login_qr_update, + login_qr_api=login_qr_api, + login_way=login_way, + ) if not identity_ready: raise RuntimeError("当前未拿到可用账号身份,请重新扫码登录") # 864 在“服务端已经在线、ABOT 只是后启动”的场景下会直接走这里: @@ -450,7 +506,15 @@ class Server864RuntimeMixin: try: await self._wait_init_ready(logger=logger) - identity_ready = await self._refresh_identity_from_profile(logger=logger) + identity_ready = await self._wait_login_identity_ready( + logger=logger, + on_login_qr_update=on_login_qr_update, + uuid=uuid, + url=url, + scan_url=scan_url, + login_qr_api=login_qr_api, + login_way=login_way, + ) if not identity_ready: raise RuntimeError("扫码完成后未获取到可用账号身份,请重新扫码登录") ipad_config["wxid"] = self.wxid