Files
abot/docs/wechat_ipad多版本Server适配路线图.md
liuwei febcc7c5ab 调整 wechat_ipad 适配器目录规划
- 将多版本适配方案调整为每个 provider 使用独立目录管理
- 移除 855 继续复用现有 client 的建议,避免新旧协议继续耦合
- 明确阶段一优先迁移 855 所需最小能力到独立 provider 目录
2026-05-07 09:39:53 +08:00

426 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/`
- `wechat_ipad/providers/server_864/`
职责:
- 各 server 版本的运行模型适配
- 各 server 版本的协议调用适配
- 各 server 版本的响应结构归一化
说明:
- 不再要求 855 继续复用现有 `wechat_ipad/client/`
- 更推荐每个 provider 自带独立目录,内部自行管理登录、消息、联系人、群信息等协议实现
- 这样可以把不同 server 的协议差异彻底隔离,避免为了兼容新版本继续污染旧 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/
│ │ ├── __init__.py
│ │ ├── provider.py
│ │ ├── login.py
│ │ ├── message.py
│ │ └── contact.py
│ └── server_864/
│ ├── __init__.py
│ ├── provider.py
│ ├── login.py
│ ├── message.py
│ └── contact.py
└── models/
```
说明:
- `gateway.py`:对 `Robot` 提供统一入口
- `provider_base.py`:定义最小约定
- `providers/legacy_855/`855/859 风格协议的独立实现目录
- `providers/server_864/`864 风格协议的独立实现目录
- 每个 provider 目录内按登录、消息、联系人等维度分文件,但只在本 provider 内部使用,不向外暴露协议细节
## 10. 推荐推进路线
### 阶段一:先搭接口,不改变现有行为
目标:
-`Robot` 依赖 Gateway
- 但底层行为先只对齐当前 855/859保证现有能力不受影响
建议步骤:
1. 新增 `gateway.py`
2. 新增 `provider_base.py`
3. 新增 `providers/legacy_855/` 目录与 `provider.py`
4. 把当前 855 所需的登录、消息、联系人能力逐步迁入该目录
5.`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。