Files
abot/docs/wechat_ipad多版本Server适配路线图.md

16 KiB
Raw Permalink Blame History

wechat_ipad 多版本 Server 适配路线图

1. 文档目标

本文档用于指导 ABOT 对接多个 wechat_ipad server 版本时的架构收敛方式,重点解决以下问题:

  • 当前项目默认绑定 855/859 风格协议,后续接入 864 等新版本时改动面过大
  • 不同 server 在登录、心跳、在线状态检测、消息同步方式上存在明显差异
  • 希望代码保持精简,不引入过多抽象层,避免阅读成本上升
  • 希望未来新增 server 时,尽量不再改动 robot.py 主链路

本文档不追求一步到位抽象“所有微信能力”,而是先定义一条适合当前项目的最小演进路线。

1.1 当前推进状态

截至当前版本,已完成以下事项:

  • 已创建基线 tagpre_server_adapter_20260507
  • 已新增 wechat_ipad/gateway.py
  • 已新增 wechat_ipad/provider_base.py
  • 已新增 providers/legacy_855/ 独立目录,并迁入当前 855/859 协议实现
  • 已将 robot.py 的接入实例化入口切换为 WechatGateway
  • 已新增 wechat_ipad/providers/legacy_855/runtime.py
  • 已将 855 的登录、历史消息拉取、心跳、长心跳、消息轮询、掉线二次登录恢复迁入 legacy_855 provider
  • 已将 robot.py 精简为“注册回调 + 业务处理”,不再直接维护 855 的运行时主循环
  • 已补上 Legacy855WechatClient 的显式初始化入口,避免 provider 多继承构造链不稳定
  • 已删除历史 wechat_ipad/client/ 目录,避免后续误回退到旧实现
  • 已为 855 登录流程补充 Dashboard 首页二维码引导态,支持未登录时自动弹窗、倒计时与最近二维码记录展示
  • 已新增 providers/server_864/ 独立目录,用于承接 864 风格 server
  • 已为 864 接入补充 wechat_ipad.server_key 统一配置项,支持通过 .envWECHAT_SERVER_KEY 注入
  • 已在 wechat_ipad/gateway.py 中注册 server_864 / 864 别名
  • 已实现 864 第一版登录、初始化等待、HTTP 消息轮询、联系人、群信息、资料与朋友圈基础接口
  • 已在 robot.py 中为 864 增加登录态硬隔离,默认不再回读 855 的历史 config.toml 与动态字段
  • 已基于真实 864 服务联调修正首批路由差异:二维码返回结构、联系人详情路由、群公告路由、二维码有效期倒计时同步
  • 已确认 864 的消息发送类接口在“尚未建立连接对象”时会优先返回“该链接不存在”,这与登录态接口返回“需要重新登录”属于不同阶段
  • 已开始把 864 的“等待服务端准备 / 需要重新登录 / 等待扫码”三态显式回传给 Dashboard避免首页把不同问题混成一类未登录提示

当前尚未完成的关键项:

  • 855 provider 仍需完成一轮“当前项目实际依赖接口”的可上线回归验证
  • 855 provider 仍需继续梳理“项目真实使用到的接口覆盖面”,确认是否还有遗漏能力未纳入 provider 目录
  • 864 provider 仍需完成真机联调,尤其是消息字段归一化、视频发送、名片发送等增强能力
  • Dashboard 仍需继续做少量多 provider 登录文案收敛,但登录状态结构已具备扩展空间

因此,当前状态可以定义为:

  • “接入入口已收口”
  • “855 运行时主链路已迁入 provider”
  • “未登录场景已有 Dashboard 可视化登录引导”
  • “864 第一版 provider 已落地,但还需要真实 server 回归验证”
  • “尚未达到 855 / 864 都可直接无差异替换现网上线的最终状态”

2. 当前问题概览

2.1 当前耦合点

当前微信接入实现仍需关注以下历史耦合点与残留影响:

  • 历史版本曾直接依赖 wechat_ipad/config.toml,当前已开始切向 config.yaml + .env
  • Robot 的实例化入口虽然已切到 WechatGateway,但配置读取与业务初始化仍在主程序中
  • 855 的运行时职责已经迁入 provider但 864 尚未接入验证,统一抽象仍需继续收敛
  • 公共 models/ 仍在服务主链路,而多版本协议实现已正式收口到 providers/*/

这导致一个结果:

  • 如果继续在 Robot 主链路里堆版本判断,后续 server 版本变化时改动面仍会再次放大

2.2 855 / 864 的核心差异

从现有 855 风格 swagger 与 864 swagger 对比看,差异已经不只是“接口路径不同”,而是“运行模型不同”。

855/859 风格通常具备以下特点:

  • 通过 wxid 驱动大多数接口调用
  • 需要客户端自己执行心跳、长心跳、在线状态维护
  • 需要客户端主动轮询同步消息
  • 登录和缓存唤醒逻辑由客户端自己串起来

864 风格目前看到的特点包括:

  • 更偏向 key + body 的请求风格
  • 登录接口命名和流程明显不同
  • 消息同步同时支持 WS 与 HTTP 轮询
  • 在线状态、保活和消息同步的职责边界更多由 server 侧承担

结论:

  • 不能只做“路径别名映射”
  • 必须把“运行时模型差异”也纳入适配层设计

3. 设计原则

后续适配设计建议遵循以下原则:

3.1 业务层不感知 server 版本

Robot、插件系统、消息归档、后台管理,不应该直接感知:

  • 当前是 855 还是 864
  • 是否需要心跳
  • 是否需要手动轮询消息
  • 鉴权参数是 wxid 还是 key

3.2 不做过厚抽象

本项目不建议引入过多层级,例如:

  • 不建议再拆 manager + service + strategy + factory + registry 多层套娃
  • 不建议一开始把所有微信能力抽成几十个接口
  • 不建议为每个 API endpoint 单独建类

目标是:

  • 层数少
  • 入口清晰
  • 新人容易顺藤摸瓜读代码

3.3 第一阶段先完成 855 全量可上线接入

考虑到当前项目已经依赖 855/859 风格能力在真实环境运行,第一阶段不能只做“主链路最小闭环”,而要做到:

  • 855 provider 能完整替代当前 Robot + 旧接入实现 的现网接入方式
  • 替换后可以直接上线运行
  • 业务行为、插件调用、后台功能、消息归档链路不发生明显退化

因此第一阶段目标应定义为:

  • 先完成 855 全量接入与运行时收口
  • 再在第二阶段接入 864

这比“先抽最小接口、后补功能”更符合当前项目实际。

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 版本的响应结构归一化

说明:

  • 不再保留旧 wechat_ipad/client/ 作为正式实现入口
  • 更推荐每个 provider 自带独立目录,内部自行管理登录、消息、联系人、群信息等协议实现
  • 这样可以把不同 server 的协议差异彻底隔离,避免为了兼容新版本继续污染历史实现

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()

6.5 855 第一阶段必须覆盖的现网能力

如果目标是“第一阶段即可上线替换”,那么 855 provider 第一版建议直接覆盖当前项目已在使用的能力,而不只是最小主链路。

至少应包含:

  • 登录 / 唤醒登录 / 登录缓存读取
  • 心跳 / 长心跳 / 二次登录恢复
  • 消息同步与消息接收分发
  • 文本消息发送
  • 图片消息发送
  • 语音消息发送
  • 视频消息发送
  • 表情消息发送
  • 链接 / 卡片 / app 消息发送
  • 撤回消息
  • 联系人列表与联系人详情
  • 用户资料与扩展资料
  • 群详情、群公告、群成员列表
  • 群邀请、拉人等当前项目已在用的群管理能力
  • 项目内已经依赖的下载或转发能力

原则:

  • 只要当前主程序、插件、后台、调度逻辑已经依赖,就纳入 855 第一阶段
  • 不要求第一阶段补齐“server 支持但项目暂未使用”的全部接口

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 结构,例如:

{
    "wxid": "...",
    "nickname": "...",
    "alias": "...",
    "phone": "...",
    "signature": "..."
}

消息列表可以统一为:

{
    "add_msgs": [...],
    "raw": {...}
}

这样做的优点:

  • 轻量
  • 阅读门槛低
  • 比强行把原始 server JSON 暴露给 Robot 更稳定

8.2 后续再考虑更强类型化

只有当 provider 数量继续增加,或者字段归一化变复杂时,再考虑引入:

  • LoginProfile
  • ChatroomInfo
  • IncomingMessageEnvelope

目前不建议一开始做太重。

9. 目录结构建议

建议控制在这个粒度:

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. 推荐推进路线

阶段一:完成 855 全量 provider 化并达到可上线状态

目标:

  • Robot 依赖 Gateway
  • providers/legacy_855/ 完整承接当前 855/859 接入能力
  • 替换后可以直接上线,不依赖历史 client 目录

建议步骤:

  1. 新增 gateway.py
  2. 新增 provider_base.py
  3. 新增 providers/legacy_855/ 目录与 provider.py
  4. 将当前项目已使用的 855 功能按模块迁入该目录:
    • login.py
    • message.py
    • contact.py
    • group.py
    • profile.py
    • runtime.py
  5. Robot 中的登录、心跳、长心跳、消息轮询、恢复逻辑迁入 855 provider
  6. robot.py 中直接依赖 WechatAPIClient 的位置改成依赖 Gateway
  7. 跑通人工回归,确认能替换现有接入链路上线

阶段结果:

  • 855 provider 完整替代旧接入实现
  • Robot 主链路与具体 server 实现解耦
  • 项目可继续按 855 方案稳定上线

阶段二:实现 864 provider 的最小闭环

目标:

  • 在不影响 855 现网运行的前提下,引入 864 provider

建议步骤:

  1. 新增 providers/server_864/
  2. 先实现登录状态获取与基础登录能力
  3. 实现 864 的消息接收策略
  4. 实现文本发送、联系人、群信息等核心能力
  5. 在 Gateway 中通过 server_type 切换 provider

阶段结果:

  • 864 可以先跑主链路
  • 高级能力后续再补

当前已完成的第一版范围:

  • 已接入固定 server_key 配置
  • 已实现二维码登录轮询与初始化等待
  • 已实现 HTTP 轮询消息同步
  • 已实现联系人、群资料、当前账号资料、朋友圈基础接口
  • 已保留与 855 尽量一致的对外方法名,便于 Robot 无感切换
  • 已补一层登录阶段探测,首页可以直接区分“等待服务端准备”“需要重新登录”“等待扫码”

当前仍待补强的范围:

  • 真实 864 server 环境下的字段回包核对
  • 视频发送、名片发送等低频接口
  • 如后续需要更低延迟,可再补 WS 同步消息 runtime

阶段三:扩展 864 与后续 provider 的高级能力

后续再逐步统一:

  • 图片消息
  • 语音消息
  • 卡片/链接消息
  • 朋友圈
  • 群管理高级动作

11. 当前最值得优先落地的改造点

如果当前目标是“尽快把架构收口,同时保证可以上线”,建议优先做以下 6 项:

  1. 新增 gateway.py
  2. providers/legacy_855/
  3. 梳理当前项目实际使用到的 855 接口清单
  4. 把运行时逻辑全部迁入 855 provider
  5. Robot 不再直接 new WechatAPIClient
  6. 做一套 855 provider 的人工回归清单,确认具备上线条件

12. 不建议当前阶段做的事情

为了避免过度设计,当前阶段不建议:

  1. 不建议一次抽象所有微信功能
  2. 不建议为每个 API endpoint 单独建类
  3. 不建议让 Robot 持续保留 if server_type == ... 的运行逻辑分叉
  4. 不建议让 864 回退复用已经移除的旧 client 结构
  5. 不建议现在就引入太多类型层、事件总线或复杂工厂模式

13. 结论

适配多版本 wechat_ipad server 的关键,不是做“更多 URL 配置”,而是把以下两类差异真正隔离开:

  • 协议差异:路径、鉴权、请求体、返回结构
  • 运行模型差异:登录方式、心跳方式、消息接收方式、掉线恢复方式

对于当前项目,最适合的方向是:

  • Robot 保持业务中心化
  • Gateway 足够薄
  • Provider 承担全部 server 差异
  • 先统一主链路,不追求一步到位

这条路线既能控制复杂度,也方便未来继续接入 864 或其他版本 server。