本次重构对微信iLink渠道插件进行了全面整理:
1. 新增共享常量模块`_constants.py`,集中管理所有跨模块共享配置与标识,对齐manifest单真相源
2. 统一缓存键格式为`wechat_ilink:{account_id}:{key}`,修复白名单存储键顺序错误
3. 重构登录适配器,移除不必要的account_id参数,简化接口调用
4. 重构生命周期相关代码,新增缓存清理逻辑,支持按账户清理孤儿缓存
5. 移除冗余重复定义的常量与配置默认值,统一从常量模块导入
6. 更新manifest配置,补充传输模式与能力要求声明
7. 优化出站适配器,新增续传支持与分片发送逻辑
158 lines
7.7 KiB
Python
158 lines
7.7 KiB
Python
"""微信 iLink(ClawBot)渠道插件入口。
|
||
|
||
实现 ``CHANNEL_ENTRY`` 契约,注册 11 个适配器与生命周期钩子,返回
|
||
``PluginManifest``。由宿主在 loaded 阶段通过 ``importlib`` 导入并调用。
|
||
|
||
调用顺序(严格):
|
||
1. ``getXxxPort`` 获取被驱动端口实例(宿主已从 manifest.accessible_ports
|
||
加载权限,无需运行时 declareXxx)。
|
||
2. 实例化 ``WeChatILinkLifecycleHandler`` 与 ``ILinkClient``。
|
||
3. 实例化并注册 11 个适配器(puller / inbound / outbound / session /
|
||
status / login / lifecycle / probeable / doctor / wizard / whitelist)。
|
||
4. ``registerLifecycleHandler`` 注册生命周期钩子(鸭子类型调用)。
|
||
5. 返回 ``PluginManifest``。
|
||
|
||
F-03 单真相源:本入口仅承接 discover 阶段解析的 ``ChannelManifest``,
|
||
不再重复构造声明性字段(capabilities / config_schema / accessible_ports /
|
||
injectable_pipelines / resource_quota / env_vars / credential_strategy 等),
|
||
所有声明性字段以 ``manifest.json`` 为唯一真相源。本函数仅负责适配器实例化、
|
||
client 实例化、LifecycleHandler 构造与 ``registerAdapter`` 调用。
|
||
|
||
适配器 DI 说明:
|
||
- ``puller`` / ``outbound`` 适配器接收 ``(client, config_port, logger_port)``:
|
||
适配器直接持有 ConfigPort 读取渠道级配置(对齐 wechat_woc 模式)。
|
||
- 4 个适配器(inbound / login / doctor / wizard)接收
|
||
``(client, logger_port)``。
|
||
- ``lifecycle`` / ``whitelist`` 适配器接收 ``(cache_port, logger_port)``:
|
||
仅做账户级缓存清理与白名单数据存储,不调用渠道侧 API,无需 ILinkClient
|
||
(对齐 wechat_woc 模式)。
|
||
- ``probeable`` 适配器接收 ``(client, persistence_port, logger_port)``:
|
||
需动态发现 account_id 调用 getconfig 探活。
|
||
- ``session`` / ``status`` 适配器无状态(INV-5),无 ``__init__`` 参数,
|
||
仅做协议转换,所有数据从 raw_event.payload 提取。
|
||
|
||
长轮询传输管理:iLink 通过 ``PullerAdapter`` 长轮询 ``getupdates`` 拉取
|
||
消息,``PullerWorker`` 由传输引擎通过 ``ChannelAccountOnline`` /
|
||
``ChannelAccountOffline`` 领域事件触发启停,``LifecycleAdapter`` 与
|
||
``LifecycleHandler`` 不自管理轮询任务。
|
||
|
||
依赖方向:仅 import ``yuxi.channels.contract.*`` + 标准库 + 同插件内部模块,
|
||
不污染框架层。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from yuxi.channels.contract.plugin.entry import PluginHost
|
||
from yuxi.channels.contract.plugin.manifest import (
|
||
ChannelManifest,
|
||
PluginManifest,
|
||
)
|
||
|
||
from .adapters.doctor_adapter import WeChatILinkDoctorAdapter
|
||
from .adapters.inbound_adapter import WeChatILinkInboundAdapter
|
||
from .adapters.lifecycle_adapter import WeChatILinkLifecycleAdapter
|
||
from .adapters.login_adapter import WeChatILinkLoginAdapter
|
||
from .adapters.outbound_adapter import WeChatILinkOutboundAdapter
|
||
from .adapters.probeable_adapter import WeChatILinkProbeableAdapter
|
||
from .adapters.puller_adapter import WeChatILinkPullerAdapter
|
||
from .adapters.session_adapter import WeChatILinkSessionAdapter
|
||
from .adapters.status_adapter import WeChatILinkStatusAdapter
|
||
from .adapters.whitelist_adapter import WeChatILinkWhitelistAdapter
|
||
from .adapters.wizard_adapter import WeChatILinkWizardAdapter
|
||
from .ilink_client import ILinkClient
|
||
from .lifecycle import WeChatILinkLifecycleHandler
|
||
|
||
# 已注册适配器类型列表(与 registerAdapter 调用顺序一致)。
|
||
# 此处为运行时适配器清单,非声明性字段,需与下方 registerAdapter 调用保持一致。
|
||
_ADAPTER_TYPES: tuple[str, ...] = (
|
||
"puller",
|
||
"inbound",
|
||
"outbound",
|
||
"session",
|
||
"status",
|
||
"login",
|
||
"lifecycle",
|
||
"probeable",
|
||
"doctor",
|
||
"wizard",
|
||
"whitelist",
|
||
)
|
||
|
||
|
||
def channel_entry(host: PluginHost, manifest: ChannelManifest) -> PluginManifest:
|
||
"""微信 iLink 渠道插件入口。
|
||
|
||
由宿主在 loaded 阶段调用,完成适配器注册、生命周期钩子注册,
|
||
返回 ``PluginManifest``。
|
||
|
||
能力边界(accessible_ports / injectable_pipelines / resource_quota /
|
||
config_schema / env_vars / credential_strategy 等)由 discover 阶段
|
||
解析的 ``manifest`` 静态字段承载,宿主在加载期通过
|
||
``PluginCapabilityChecker.check`` 校验,运行时通过
|
||
``PluginHostImpl._checkPortAccess`` 从 manifest 读取并强制约束。本函数
|
||
不重复构造声明性字段(F-03 单真相源)。
|
||
|
||
参数:
|
||
host: 插件宿主,提供端口获取与扩展点注册 API。
|
||
manifest: 渠道清单,由 discover 阶段从 ``manifest.json`` 解析得到,
|
||
承载所有声明性字段。本函数复用其 ``config_schema`` 注入
|
||
``LifecycleHandler``,并直接作为返回 ``PluginManifest.manifest``。
|
||
"""
|
||
|
||
# 1. 获取端口实例(宿主已从 manifest.accessible_ports 加载权限)
|
||
# ILinkClient 仅依赖 ConfigPort/CachePort/LoggerPort(凭证由
|
||
# CredentialService 通过 ConfigPort→CachePort 管理);
|
||
# PersistencePort 供 ProbeableAdapter 动态发现 account_id。
|
||
config_port = host.getConfigPort()
|
||
logger_port = host.getLoggerPort()
|
||
cache_port = host.getCachePort()
|
||
persistence_port = host.getPersistencePort()
|
||
|
||
# 2. 实例化 ILinkClient 与 LifecycleHandler
|
||
# 依赖关系为单向:handler 在 onInit 调 client.attach_http_client 注入连接池,
|
||
# client 不引用 handler。先创建 client,再创建 handler 并通过构造器注入。
|
||
# config_schema / max_connections 取自 manifest(F-03 单真相源)。
|
||
client = ILinkClient(config_port, cache_port, logger_port)
|
||
handler = WeChatILinkLifecycleHandler(
|
||
config_port,
|
||
logger_port,
|
||
cache_port,
|
||
manifest.config_schema,
|
||
client,
|
||
max_connections=(manifest.resource_quota.max_connections if manifest.resource_quota is not None else 10),
|
||
)
|
||
|
||
# 3. 实例化并注册 11 个适配器
|
||
# puller / outbound 接收 (client, config_port, logger_port):
|
||
# 适配器直接持有 ConfigPort 读取渠道级配置(对齐 wechat_woc 模式)。
|
||
# inbound / login / doctor / wizard 接收 (client, logger_port);
|
||
# lifecycle / whitelist 接收 (cache_port, logger_port)(账户级缓存清理,
|
||
# 不调用渠道侧 API,对齐 wechat_woc 模式);
|
||
# probeable 接收 (client, persistence_port, logger_port);
|
||
# session / status 无状态。
|
||
host.registerAdapter("puller", WeChatILinkPullerAdapter(client, config_port, logger_port))
|
||
host.registerAdapter("inbound", WeChatILinkInboundAdapter(client, logger_port))
|
||
host.registerAdapter("outbound", WeChatILinkOutboundAdapter(client, config_port, logger_port))
|
||
host.registerAdapter("session", WeChatILinkSessionAdapter())
|
||
host.registerAdapter("status", WeChatILinkStatusAdapter())
|
||
host.registerAdapter("login", WeChatILinkLoginAdapter(client, logger_port))
|
||
host.registerAdapter("lifecycle", WeChatILinkLifecycleAdapter(cache_port, logger_port))
|
||
host.registerAdapter("probeable", WeChatILinkProbeableAdapter(client, persistence_port, logger_port))
|
||
host.registerAdapter("doctor", WeChatILinkDoctorAdapter(client, logger_port))
|
||
host.registerAdapter("wizard", WeChatILinkWizardAdapter(client, logger_port))
|
||
host.registerAdapter("whitelist", WeChatILinkWhitelistAdapter(cache_port, logger_port))
|
||
|
||
# 4. 注册生命周期钩子
|
||
# PluginHost Protocol 未声明 registerLifecycleHandler,但 PluginHostImpl
|
||
# 已实现,运行时通过鸭子类型调用。
|
||
host.registerLifecycleHandler(handler)
|
||
|
||
# 5. 返回 PluginManifest(manifest 直接复用入参,adapters 为运行时清单)
|
||
return PluginManifest(
|
||
manifest=manifest,
|
||
adapters=_ADAPTER_TYPES,
|
||
)
|
||
|
||
|
||
CHANNEL_ENTRY = channel_entry
|