From 712dda5b41b8b83001d7598d97567955e4408282 Mon Sep 17 00:00:00 2001 From: liuwei Date: Thu, 7 May 2026 09:52:27 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A9=20Robot=20=E6=8E=A5=E5=85=A5=20Wechat?= =?UTF-8?q?Gateway=20=E5=B9=B6=E5=90=8C=E6=AD=A5=E6=8E=A8=E8=BF=9B?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 WechatGateway 增加属性写透传,兼容现有 ipad_bot 属性赋值方式 - 将 Robot 的 wechat 接入实例化入口切换为 Gateway,并默认走 legacy_855 provider - 在适配路线图中补充当前推进状态,明确已完成项与待迁移运行时职责 --- docs/wechat_ipad多版本Server适配路线图.md | 22 ++++++++++++++++++++++ robot.py | 15 ++++++++++++--- wechat_ipad/gateway.py | 11 +++++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/docs/wechat_ipad多版本Server适配路线图.md b/docs/wechat_ipad多版本Server适配路线图.md index d07bae5..a623b61 100644 --- a/docs/wechat_ipad多版本Server适配路线图.md +++ b/docs/wechat_ipad多版本Server适配路线图.md @@ -11,6 +11,28 @@ 本文档不追求一步到位抽象“所有微信能力”,而是先定义一条适合当前项目的最小演进路线。 +## 1.1 当前推进状态 + +截至当前版本,已完成以下事项: + +- 已创建基线 tag:`pre_server_adapter_20260507` +- 已新增 [wechat_ipad/gateway.py](/d:/learn/abot/wechat_ipad/gateway.py:1) +- 已新增 [wechat_ipad/provider_base.py](/d:/learn/abot/wechat_ipad/provider_base.py:1) +- 已新增 `providers/legacy_855/` 独立目录,并迁入当前 855/859 协议实现 +- 已将 [robot.py](/d:/learn/abot/robot.py:1) 的接入实例化入口切换为 `WechatGateway` + +当前尚未完成的关键项: + +- `Robot` 中的登录、心跳、长心跳、消息轮询、掉线恢复逻辑仍未完全迁入 855 provider +- `legacy_855` 目录内尚未补充独立的 `runtime.py` 收口运行时模型 +- 855 provider 仍需完成一轮“当前项目实际依赖接口”的可上线回归验证 + +因此,当前状态可以定义为: + +- “接入入口已收口” +- “运行时主链路迁移进行中” +- “尚未达到 855 可直接替换现网上线的最终状态” + ## 2. 当前问题概览 ### 2.1 当前耦合点 diff --git a/robot.py b/robot.py index 120ecf1..426e3ff 100644 --- a/robot.py +++ b/robot.py @@ -33,7 +33,7 @@ from utils.wechat.member_monitor import ChatroomMemberMonitor from utils.wechat.message_to_db import MessageStorage from utils.ai.llm_registry import LLMRegistry from utils.trace_context import set_current_trace_id, reset_current_trace_id -from wechat_ipad import WechatAPIClient +from wechat_ipad import WechatAPIClient, WechatGateway from wechat_ipad.models.message import WxMessage, MessageType # 定义全局信号量,限制最大并发 10 @@ -233,6 +233,11 @@ class Robot: server_ip = self.ipad_config.get("server_ip", "") server_port = self.ipad_config.get("server_port", 8059) + # 当前阶段先通过 Gateway 承接 provider 选择: + # 1. 默认仍走 legacy_855,保持现有现网协议行为; + # 2. 这里提前把入口收敛到 Gateway,后续接 864 时可不再修改主链路; + # 3. `server_type` 缺失时自动回退 legacy_855,兼容现有 config.toml。 + # 创建事件循环 self.ipad_loop = asyncio.new_event_loop() @@ -259,8 +264,12 @@ class Robot: """wechat_ipad核心逻辑,基于bot-core.py""" try: self.LOG.debug("启动wechat_ipad bot") - # 调用登录接口 - self.ipad_bot = wechat_ipad.WechatAPIClient(server_ip, server_port) + # 调用登录接口: + # 1. 这里不再直接实例化具体客户端实现,而是统一通过 Gateway 选择 provider; + # 2. 第一阶段仍默认绑定 legacy_855,后续接入 864 时这里只需要读新配置即可; + # 3. 通过 Gateway 的属性透传能力,先尽量保持现有 `self.ipad_bot.xxx` 写法不变。 + server_type = str(self.ipad_config.get("server_type", "legacy_855") or "legacy_855").strip() + self.ipad_bot = WechatGateway(server_ip, server_port, server_type=server_type) self.message_auto_revoke = MessageAutoRevoke(self.ipad_bot) wxid = self.ipad_config.get("wxid", "") device_name = self.ipad_config.get("device_name", "") diff --git a/wechat_ipad/gateway.py b/wechat_ipad/gateway.py index 94b6c7f..c587a88 100644 --- a/wechat_ipad/gateway.py +++ b/wechat_ipad/gateway.py @@ -17,6 +17,7 @@ class WechatGateway: "855": Legacy855WechatClient, "859": Legacy855WechatClient, } + _LOCAL_ATTRS = {"server_type", "provider"} def __init__(self, ip: str, port: int, server_type: str = "legacy_855", **kwargs: Any): normalized_server_type = str(server_type or "legacy_855").strip().lower() @@ -24,10 +25,16 @@ class WechatGateway: if provider_cls is None: raise ValueError(f"不支持的 wechat provider 类型: {server_type}") - self.server_type = normalized_server_type - self.provider = provider_cls(ip=ip, port=port, **kwargs) + object.__setattr__(self, "server_type", normalized_server_type) + object.__setattr__(self, "provider", provider_cls(ip=ip, port=port, **kwargs)) def __getattr__(self, item: str) -> Any: """将未显式实现的属性/方法透传给具体 Provider。""" return getattr(self.provider, item) + def __setattr__(self, key: str, value: Any) -> None: + """将运行期动态属性写入透传给 Provider,保持旧调用面的兼容性。""" + if key in self._LOCAL_ATTRS or "provider" not in self.__dict__: + object.__setattr__(self, key, value) + return + setattr(self.provider, key, value)