ForcePilot/backend/package/yuxi/channels/plugins/wechat_ilink/entry.py

158 lines
7.7 KiB
Python
Raw Normal View History

"""微信 iLinkClawBot渠道插件入口。
实现 ``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 取自 manifestF-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. 返回 PluginManifestmanifest 直接复用入参adapters 为运行时清单)
return PluginManifest(
manifest=manifest,
adapters=_ADAPTER_TYPES,
)
CHANNEL_ENTRY = channel_entry