支持864登录二维码切换与退出重登

This commit is contained in:
liuwei
2026-05-07 15:39:48 +08:00
parent 1f7dedf866
commit 41a2bd9358
4 changed files with 266 additions and 3 deletions

View File

@@ -927,9 +927,106 @@ class Robot:
if hasattr(self, "ipad_bot") and self.ipad_bot and hasattr(self.ipad_bot, "stop_runtime"):
self.ipad_bot.stop_runtime()
if self.ipad_loop:
self.ipad_loop.stop()
try:
# 事件循环运行在独立线程里,主线程这里需要走线程安全停止:
# 1. 直接 `loop.stop()` 在某些时机会留下竞态,导致旧线程迟迟不退出;
# 2. Dashboard 现在需要支持“不重启主进程,直接切换 864 登录模式”;
# 3. 因此这里改成 `call_soon_threadsafe`,让旧 provider 能更稳地收尾退出。
self.ipad_loop.call_soon_threadsafe(self.ipad_loop.stop)
except Exception:
self.ipad_loop.stop()
if self.ipad_thread and self.ipad_thread.is_alive():
self.ipad_thread.join(timeout=5)
self.ipad_thread = None
self.ipad_loop = None
self.ipad_bot = None
self.LOG.info("wechat_ipad客户端已停止")
def switch_server_864_login_entry(self, *, login_qr_api: str, login_way: str | None = None, do_logout: bool = True) -> dict:
"""切换 864 登录入口并重启登录流程。
设计说明:
1. 用户希望在后台直接切换“鸿蒙专用二维码”和“标准 New 二维码”,而不是改 `.env` 后重启整套服务;
2. 当前 864 runtime 在独立线程里长驻运行,最稳妥的切换方式是“更新配置 -> 退出旧登录态 -> 重启 provider 登录线程”;
3. 这样实现虽然比纯运行时热切换更直接,但代码层次更浅,也更便于后续继续接其他 server 变体。
"""
if not isinstance(self.ipad_config, dict):
raise RuntimeError("wechat_ipad 运行时配置尚未初始化,暂时无法切换 864 登录入口")
current_server_type = self._normalize_wechat_provider_key(self.ipad_config.get("server_type", "legacy_855"))
if current_server_type != "server_864":
raise RuntimeError("当前仅支持在 server_864 模式下切换登录二维码入口")
normalized_login_qr_api = str(login_qr_api or "").strip().lower()
if normalized_login_qr_api not in {"harmony_api", "new", "new_x"}:
raise ValueError(f"不支持的 864 登录入口模式: {login_qr_api}")
normalized_login_way = str(login_way or self.ipad_config.get("login_way", "mac") or "mac").strip().lower()
if normalized_login_qr_api == "harmony_api":
normalized_login_way = "harmony"
if do_logout and self.ipad_bot and self.ipad_loop:
try:
logout_future = asyncio.run_coroutine_threadsafe(self.ipad_bot.log_out(), self.ipad_loop)
logout_future.result(timeout=20)
except Exception as e:
# 切换登录模式时,退出旧会话失败不应阻断后续重启:
# 1. 某些 864 版本在会话已失效时会直接返回错误;
# 2. 用户真正关心的是“后台能否尽快切到新的二维码入口”;
# 3. 因此这里记录日志后继续向下执行重启流程。
self.LOG.warning(f"切换 864 登录入口前执行退出请求失败,继续重启登录流程: {e}")
self.ipad_config["login_qr_api"] = normalized_login_qr_api
self.ipad_config["login_way"] = normalized_login_way
if isinstance(getattr(self.config, "wechat_ipad", None), dict):
self.config.wechat_ipad["login_qr_api"] = normalized_login_qr_api
self.config.wechat_ipad["login_way"] = normalized_login_way
self._clear_ipad_identity_cache()
switch_label_map = {
"harmony_api": "864 鸿蒙专用二维码",
"new": "864 标准 New 二维码",
"new_x": f"864 NewX 二维码({normalized_login_way}",
}
with self._ipad_login_qr_lock:
self.ipad_login_qr_state = {
"logged_in": False,
"active": True,
"status": "waiting",
"provider_name": "server_864",
"provider_stage": "login_required",
"connection_ready": False,
"login_required": True,
"status_text": f"正在切换到{switch_label_map.get(normalized_login_qr_api, normalized_login_qr_api)},请稍候刷新二维码",
"current": {
"login_qr_api": normalized_login_qr_api,
"login_way": normalized_login_way,
"updated_at": time.time(),
"updated_at_text": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
},
"history": [],
"updated_at": time.time(),
}
self.stop_wechat_ipad()
if not self.init_wechat_ipad():
raise RuntimeError("重启 wechat_ipad 登录线程失败,请检查 864 服务端与配置")
return {
"server_type": "server_864",
"login_qr_api": normalized_login_qr_api,
"login_way": normalized_login_way,
"message": switch_label_map.get(normalized_login_qr_api, normalized_login_qr_api),
}
def logout_server_864_and_restart_login(self) -> dict:
"""退出当前 864 登录态,并按现有二维码入口重新进入登录引导。"""
return self.switch_server_864_login_entry(
login_qr_api=str(self.ipad_config.get("login_qr_api", "new_x") or "new_x"),
login_way=str(self.ipad_config.get("login_way", "mac") or "mac"),
do_logout=True,
)
def keep_running_and_block_process(self) -> None:
"""
保持机器人运行,不让进程退出