From c1b7118d3284d73eef3e323736613b638c09ca3b Mon Sep 17 00:00:00 2001 From: liuwei Date: Thu, 7 May 2026 09:35:58 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=20wechat=5Fipad=20=E5=A4=9A?= =?UTF-8?q?=E7=89=88=E6=9C=AC=20Server=20=E9=80=82=E9=85=8D=E8=B7=AF?= =?UTF-8?q?=E7=BA=BF=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 梳理 855/864 在登录、心跳、消息同步上的运行模型差异 - 明确 Gateway + Provider 的轻量适配架构与最小统一接口 - 给出 Robot 解耦、855 收口、864 接入的分阶段推进方案 --- docs/wechat_ipad多版本Server适配路线图.md | 415 ++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 docs/wechat_ipad多版本Server适配路线图.md diff --git a/docs/wechat_ipad多版本Server适配路线图.md b/docs/wechat_ipad多版本Server适配路线图.md new file mode 100644 index 0000000..701fc31 --- /dev/null +++ b/docs/wechat_ipad多版本Server适配路线图.md @@ -0,0 +1,415 @@ +# wechat_ipad 多版本 Server 适配路线图 + +## 1. 文档目标 + +本文档用于指导 ABOT 对接多个 `wechat_ipad server` 版本时的架构收敛方式,重点解决以下问题: + +- 当前项目默认绑定 855/859 风格协议,后续接入 864 等新版本时改动面过大 +- 不同 server 在登录、心跳、在线状态检测、消息同步方式上存在明显差异 +- 希望代码保持精简,不引入过多抽象层,避免阅读成本上升 +- 希望未来新增 server 时,尽量不再改动 `robot.py` 主链路 + +本文档不追求一步到位抽象“所有微信能力”,而是先定义一条适合当前项目的最小演进路线。 + +## 2. 当前问题概览 + +### 2.1 当前耦合点 + +当前微信接入实现存在以下特点: + +- [robot.py](/d:/learn/abot/robot.py:221) 直接读取 `wechat_ipad/config.toml` +- [robot.py](/d:/learn/abot/robot.py:263) 直接实例化 `wechat_ipad.WechatAPIClient` +- `Robot` 自己承担了登录、心跳、长心跳、消息轮询、掉线恢复等运行时职责 +- `wechat_ipad/client/*.py` 直接面向当前 server 协议编写,接口路径、请求体、返回结构都写死 + +这导致一个结果: + +- 一旦 server 版本变化,不只是 `client` 要改,`Robot` 主链路也要跟着改 + +### 2.2 855 / 864 的核心差异 + +从现有 855 风格 swagger 与 864 swagger 对比看,差异已经不只是“接口路径不同”,而是“运行模型不同”。 + +855/859 风格通常具备以下特点: + +- 通过 `wxid` 驱动大多数接口调用 +- 需要客户端自己执行心跳、长心跳、在线状态维护 +- 需要客户端主动轮询同步消息 +- 登录和缓存唤醒逻辑由客户端自己串起来 + +864 风格目前看到的特点包括: + +- 更偏向 `key + body` 的请求风格 +- 登录接口命名和流程明显不同 +- 消息同步接口不再与 855 完全一致 +- 在线状态、保活和消息同步的职责边界可能由 server 侧承担更多 + +结论: + +- 不能只做“路径别名映射” +- 必须把“运行时模型差异”也纳入适配层设计 + +## 3. 设计原则 + +后续适配设计建议遵循以下原则: + +### 3.1 业务层不感知 server 版本 + +`Robot`、插件系统、消息归档、后台管理,不应该直接感知: + +- 当前是 855 还是 864 +- 是否需要心跳 +- 是否需要手动轮询消息 +- 鉴权参数是 `wxid` 还是 `key` + +### 3.2 不做过厚抽象 + +本项目不建议引入过多层级,例如: + +- 不建议再拆 `manager + service + strategy + factory + registry` 多层套娃 +- 不建议一开始把所有微信能力抽成几十个接口 +- 不建议为每个 API endpoint 单独建类 + +目标是: + +- 层数少 +- 入口清晰 +- 新人容易顺藤摸瓜读代码 + +### 3.3 先统一主链路,再扩展高级能力 + +第一阶段只统一机器人运行必需能力: + +- 登录 +- 在线状态检查 +- 消息接收 +- 文本发送 +- 用户资料 +- 联系人列表 +- 群信息和群成员 + +图片、语音、卡片、朋友圈等能力可以后续逐步补齐。 + +## 4. 推荐架构 + +建议采用“两层半”结构: + +### 4.1 第一层:业务层 + +即现有机器人主逻辑: + +- `Robot` +- 插件系统 +- 消息归档 +- 调度系统 +- Dashboard + +这一层只依赖一个统一微信网关,不直接依赖具体 server 协议。 + +### 4.2 第二层:Gateway 层 + +建议新增一个轻量入口,例如: + +- `wechat_ipad/gateway.py` + +职责只保留两项: + +1. 根据配置选择 provider +2. 对外暴露统一调用入口 + +Gateway 不负责: + +- 心跳逻辑 +- 消息轮询逻辑 +- 协议差异判断 +- 各版本字段转换细节 + +### 4.3 第三层:Provider 层 + +建议新增: + +- `wechat_ipad/provider_base.py` +- `wechat_ipad/providers/legacy_855.py` +- `wechat_ipad/providers/server_864.py` + +职责: + +- 各 server 版本的运行模型适配 +- 各 server 版本的协议调用适配 +- 各 server 版本的响应结构归一化 + +说明: + +- 855 provider 内部可以继续复用现有 `wechat_ipad/client/` +- 864 provider 不建议强行复用旧 client,建议独立实现 + +## 5. 为什么要把“运行模型”抽出来 + +这是本轮适配设计最关键的一点。 + +### 5.1 855 的运行模型 + +855/859 风格更接近“主动轮询型 provider”: + +- 需要自己发心跳 +- 需要自己发长心跳 +- 需要自己检查掉线 +- 需要自己轮询 `sync_message` +- 需要自己在登录失败时做唤醒或二次恢复 + +### 5.2 864 的运行模型 + +864 风格更可能是“轻保活 / 被动事件型 provider”: + +- 未必需要客户端主动心跳 +- 在线状态检查方式不同 +- 消息同步方式可能不是旧版的手动轮询 +- 可能通过 HTTP 新接口或 WS 模式获取消息 + +因此,不能要求所有 provider 都暴露完全相同的“内部实现”,只能要求它们提供相同的“对外能力接口”。 + +## 6. 最小统一接口建议 + +建议不要统一“所有底层动作”,而统一“Robot 真正需要的能力”。 + +### 6.1 生命周期接口 + +- `initialize()` +- `start_runtime()` +- `stop_runtime()` + +说明: + +- `start_runtime()` 是核心抽象 +- 855 provider 内部可以在这里启动心跳、长心跳、轮询任务 +- 864 provider 内部可以在这里建立消息监听或执行轻量状态检查 + +### 6.2 登录与状态接口 + +- `is_logged_in()` +- `ensure_login()` +- `get_login_identity()` + +### 6.3 消息入口接口 + +- `set_message_handler(handler)` + +说明: + +- 上层统一注册消息处理回调 +- provider 自己决定如何拿消息 +- 不再强行要求所有 provider 都暴露相同的 `sync_message()` 轮询接口给 `Robot` + +### 6.4 主动调用接口 + +- `send_text()` +- `get_profile()` +- `get_profile_ext()` +- `get_contact_list()` +- `get_contact_detail()` +- `get_chatroom_info()` +- `get_chatroom_member_list()` + +## 7. 消息同步策略如何统一 + +### 7.1 不统一“消息获取方式” + +不要要求所有 provider 都必须靠: + +- `sync_message()` + +来向上层提供消息。 + +因为: + +- 855 是主动轮询 +- 864 可能是新 HTTP 同步接口 +- 未来还可能出现 WS 推送模型 + +### 7.2 统一“消息交付方式” + +建议统一成: + +- provider 拿到消息后,调用统一的 message handler + +即: + +- 上层统一消费消息 +- 下层各自决定怎么取消息 + +这样可以把“消息来源差异”完全收敛在 provider 内部。 + +## 8. 数据归一化建议 + +为了避免业务层继续面对不同 server 的原始 JSON,建议 provider 对以下结果做轻量归一化。 + +### 8.1 第一阶段先用统一 dict + +当前项目不必急着上很多 dataclass。 + +第一阶段建议直接统一为内部 dict 结构,例如: + +```python +{ + "wxid": "...", + "nickname": "...", + "alias": "...", + "phone": "...", + "signature": "..." +} +``` + +消息列表可以统一为: + +```python +{ + "add_msgs": [...], + "raw": {...} +} +``` + +这样做的优点: + +- 轻量 +- 阅读门槛低 +- 比强行把原始 server JSON 暴露给 `Robot` 更稳定 + +### 8.2 后续再考虑更强类型化 + +只有当 provider 数量继续增加,或者字段归一化变复杂时,再考虑引入: + +- `LoginProfile` +- `ChatroomInfo` +- `IncomingMessageEnvelope` + +目前不建议一开始做太重。 + +## 9. 目录结构建议 + +建议控制在这个粒度: + +```text +wechat_ipad/ +├── gateway.py +├── provider_base.py +├── providers/ +│ ├── legacy_855.py +│ └── server_864.py +├── client/ +│ └── ... # 当前 855/859 协议实现,暂时保留 +└── models/ +``` + +说明: + +- `gateway.py`:对 `Robot` 提供统一入口 +- `provider_base.py`:定义最小约定 +- `providers/legacy_855.py`:封装旧版实现 +- `providers/server_864.py`:独立实现 864 协议适配 +- `client/`:作为旧版协议工具层保留 + +## 10. 推荐推进路线 + +### 阶段一:先搭接口,不改变现有行为 + +目标: + +- 让 `Robot` 依赖 Gateway +- 但底层仍然走当前 855/859 的 `WechatAPIClient` + +建议步骤: + +1. 新增 `gateway.py` +2. 新增 `provider_base.py` +3. 新增 `providers/legacy_855.py` +4. 把 `robot.py` 中直接依赖 `WechatAPIClient` 的位置改成依赖 Gateway + +阶段结果: + +- 行为不变 +- 但主链路与具体 server 实现开始解耦 + +### 阶段二:把运行时逻辑从 Robot 挪到 provider + +目标: + +- `Robot` 不再持有 855 专属的心跳 / 轮询 / 掉线恢复细节 + +建议步骤: + +1. 把心跳逻辑迁入 `legacy_855.py` +2. 把长心跳逻辑迁入 `legacy_855.py` +3. 把消息轮询逻辑迁入 `legacy_855.py` +4. `Robot` 只保留统一的消息处理入口,例如 `on_message(...)` + +阶段结果: + +- 855 的运行模型被收口到 provider 内部 +- 为 864 provider 留出实现空间 + +### 阶段三:实现 864 provider 的最小闭环 + +目标: + +- 先支持最小可运行能力,而不是一次支持所有接口 + +建议先实现: + +1. 登录状态获取 +2. 基础登录/唤醒逻辑 +3. 消息接收 +4. 文本发送 +5. 获取个人资料 +6. 获取联系人列表 +7. 获取群信息和群成员 + +阶段结果: + +- 864 可以先跑主链路 +- 高级能力后续再补 + +### 阶段四:扩展高级能力 + +后续再逐步统一: + +- 图片消息 +- 语音消息 +- 卡片/链接消息 +- 朋友圈 +- 群管理高级动作 + +## 11. 当前最值得优先落地的改造点 + +如果要把任务压缩成最小可执行版本,建议优先做以下 5 项: + +1. 新增 `gateway.py` +2. 抽 `legacy_855.py` +3. 让 `Robot` 不再直接 new `WechatAPIClient` +4. 把心跳和消息轮询迁入 `legacy_855.py` +5. 把 `Robot` 统一成“收到标准消息后处理业务” + +## 12. 不建议当前阶段做的事情 + +为了避免过度设计,当前阶段不建议: + +1. 不建议一次抽象所有微信功能 +2. 不建议为每个 API endpoint 单独建类 +3. 不建议让 `Robot` 持续保留 `if server_type == ...` 的运行逻辑分叉 +4. 不建议强行让 864 复用当前 `client/*.py` +5. 不建议现在就引入太多类型层、事件总线或复杂工厂模式 + +## 13. 结论 + +适配多版本 `wechat_ipad server` 的关键,不是做“更多 URL 配置”,而是把以下两类差异真正隔离开: + +- 协议差异:路径、鉴权、请求体、返回结构 +- 运行模型差异:登录方式、心跳方式、消息接收方式、掉线恢复方式 + +对于当前项目,最适合的方向是: + +- `Robot` 保持业务中心化 +- Gateway 足够薄 +- Provider 承担全部 server 差异 +- 先统一主链路,不追求一步到位 + +这条路线既能控制复杂度,也方便未来继续接入 864 或其他版本 server。