1. 新增WeChatWocStreamConnectorAdapter,实现SSE长连接接收消息,支持热更新配置 2. 升级wechat_woc插件依赖bridge版本至1.5.0,开启both传输模式 3. 新增SSE相关常量与配置项,完善woc_bridge_client SSE实现 4. 重构RouteStage,复用会话缓存避免重复查询 5. 新增入站/出站全链路日志打点,优化异常场景日志输出 6. 实现入站幂等记录状态回写机制,独立事务避免死锁 7. 新增TransportManager重启恢复逻辑,自动恢复在线账号传输任务 8. 修复inbound_pipeline移除冗余persistence_port参数,注入idempotency仓储 9. 新增InboundContext.idempotency_record_id字段,传递幂等记录主键
188 lines
9.4 KiB
Python
188 lines
9.4 KiB
Python
"""微信 wechat_woc(WechatOnCloud)渠道插件入口。
|
||
|
||
实现 ``CHANNEL_ENTRY`` 契约,注册 13 个适配器与生命周期钩子,返回
|
||
``PluginManifest``。由宿主在 loaded 阶段通过 ``importlib`` 导入并调用。
|
||
|
||
调用顺序(严格,违反顺序将触发 ``PermissionDeniedError``):
|
||
1. 获取端口实例(仅在 manifest ``accessible_ports`` 声明集合内取用,
|
||
宿主在 ``PluginHostImpl._checkPortAccess`` 中校验)。
|
||
2. 实例化 ``WocBridgeClient`` 与 ``WeChatWocLifecycleHandler``。
|
||
3. 注册 13 个适配器(puller / stream_connector / inbound / outbound /
|
||
session / status / login / lifecycle / probeable / doctor / wizard /
|
||
whitelist / directory)。
|
||
4. 注册生命周期钩子(鸭子类型调用)。
|
||
5. 返回 ``PluginManifest``(能力边界由 manifest 字段静态声明,宿主在加载
|
||
期通过 ``PluginCapabilityChecker.check`` 校验)。
|
||
|
||
F-03 单真相源:本入口仅承接 discover 阶段解析的 ``ChannelManifest``,
|
||
不再重复构造声明性字段(capabilities / config_schema / accessible_ports /
|
||
injectable_pipelines / resource_quota / env_vars / credential_strategy 等),
|
||
所有声明性字段以 ``manifest.json`` 为唯一真相源。本函数仅负责适配器实例化、
|
||
client 实例化、LifecycleHandler 构造与 ``registerAdapter`` 调用。
|
||
|
||
适配器 DI 说明:
|
||
- ``puller`` 接收 ``(client, config_port, logger_port)``:需从 ConfigPort
|
||
读取 ``poll_interval_ms`` / ``max_batch_size``。
|
||
- ``stream_connector`` 接收 ``(client, config_port, logger_port)``:SSE
|
||
长连接由 ``WocBridgeClient.stream_messages`` 建立,需 ConfigPort 读取
|
||
``sse_heartbeat_interval_ms`` / ``sse_connect_timeout_ms`` / ``max_batch_size``。
|
||
- ``outbound`` 接收 ``(client, config_port, logger_port)``:需从 ConfigPort
|
||
CHANNEL 作用域读取 ``max_message_length``(P2-2)。
|
||
- ``inbound`` / ``doctor`` / ``wizard`` / ``directory`` 接收
|
||
``(client, logger_port)``:仅做协议转换。
|
||
- ``login`` 接收 ``(client, logger_port)``:扫码状态由 ``QrLoginService``
|
||
承载,适配器不缓存登录态。
|
||
- ``lifecycle`` 接收 ``(cache_port, logger_port)``:账户删除/禁用时清理
|
||
CachePort 缓存,不调用 bridge API。
|
||
- ``probeable`` 接收 ``(client, persistence_port, logger_port)``:需动态
|
||
发现 account_id 调用 bridge ``/api/status`` 探活。
|
||
- ``whitelist`` 接收 ``(cache_port, logger_port)``:白名单数据本地存储于
|
||
CachePort,不调用 bridge API。
|
||
- ``session`` / ``status`` 适配器无状态(INV-5),无 ``__init__`` 参数,
|
||
仅做协议转换,所有数据从 raw_event.payload 提取。
|
||
|
||
传输管理:wechat_woc 通过 ``TransportManager`` 的 ``both`` 模式管理消息
|
||
接收(manifest ``transport_mode: "both"``):
|
||
- ``StreamWorker``(优先):通过 ``WeChatWocStreamConnectorAdapter`` 建立
|
||
SSE 长连接实时接收消息(bridge ≥ 1.5.0),端到端延迟 ≤1s
|
||
- ``PullerWorker``(降级):SSE 不可用或 bridge < 1.5.0 时降级为短轮询
|
||
``/api/messages/since``(2s 间隔)
|
||
两者由传输引擎通过 ``ChannelAccountOnline`` / ``ChannelAccountOffline``
|
||
领域事件触发启停,``LifecycleAdapter`` 与 ``LifecycleHandler`` 不自管理
|
||
传输任务(决策 3)。
|
||
|
||
依赖方向:仅 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.capability_prover import WocCapabilityProver
|
||
from .adapters.directory_adapter import WeChatWocDirectoryAdapter
|
||
from .adapters.doctor_adapter import WeChatWocDoctorAdapter
|
||
from .adapters.inbound_adapter import WeChatWocInboundAdapter
|
||
from .adapters.lifecycle_adapter import WeChatWocLifecycleAdapter
|
||
from .adapters.login_adapter import WeChatWocLoginAdapter
|
||
from .adapters.outbound_adapter import WeChatWocOutboundAdapter
|
||
from .adapters.probeable_adapter import WeChatWocProbeableAdapter
|
||
from .adapters.puller_adapter import WeChatWocPullerAdapter
|
||
from .adapters.session_adapter import WeChatWocSessionAdapter
|
||
from .adapters.status_adapter import WeChatWocStatusAdapter
|
||
from .adapters.stream_connector_adapter import WeChatWocStreamConnectorAdapter
|
||
from .adapters.whitelist_adapter import WeChatWocWhitelistAdapter
|
||
from .adapters.wizard_adapter import WeChatWocWizardAdapter
|
||
from ._constants import DEFAULT_MAX_CONNECTIONS
|
||
from .lifecycle import WeChatWocLifecycleHandler
|
||
from .woc_bridge_client import WocBridgeClient
|
||
|
||
# 已注册适配器类型列表(与 registerAdapter 调用顺序一致)。
|
||
# 此处为运行时适配器清单,非声明性字段,需与下方 registerAdapter 调用保持一致。
|
||
_ADAPTER_TYPES: tuple[str, ...] = (
|
||
"puller",
|
||
"stream_connector",
|
||
"inbound",
|
||
"outbound",
|
||
"session",
|
||
"status",
|
||
"login",
|
||
"lifecycle",
|
||
"probeable",
|
||
"doctor",
|
||
"wizard",
|
||
"whitelist",
|
||
"directory",
|
||
)
|
||
|
||
|
||
def channel_entry(host: PluginHost, manifest: ChannelManifest) -> PluginManifest:
|
||
"""微信 wechat_woc 渠道插件入口。
|
||
|
||
由宿主在 loaded 阶段调用,完成端口获取、客户端与生命周期钩子实例化、
|
||
适配器注册,返回 ``PluginManifest``。能力边界(accessible_ports /
|
||
injectable_pipelines / resource_quota / config_schema / env_vars /
|
||
credential_strategy 等)由 discover 阶段解析的 ``manifest`` 静态字段
|
||
承载,宿主在加载期通过 ``PluginCapabilityChecker.check`` 校验,本函数
|
||
不重复构造声明性字段(F-03 单真相源)。
|
||
|
||
参数:
|
||
host: 插件宿主,提供端口获取与扩展点注册 API。
|
||
manifest: 渠道清单,由 discover 阶段从 ``manifest.json`` 解析得到,
|
||
承载所有声明性字段。本函数复用其 ``config_schema`` 注入
|
||
``LifecycleHandler``,并直接作为返回 ``PluginManifest.manifest``。
|
||
"""
|
||
|
||
# 1. 获取端口实例(仅在 manifest accessible_ports 声明集合内取用)
|
||
# WocBridgeClient 仅依赖 ConfigPort/CachePort/LoggerPort(bridge_url
|
||
# 由 CredentialService 通过 ConfigPort→CachePort 管理);
|
||
# PersistencePort 供 ProbeableAdapter 动态发现 account_id。
|
||
config_port = host.getConfigPort()
|
||
logger_port = host.getLoggerPort()
|
||
cache_port = host.getCachePort()
|
||
persistence_port = host.getPersistencePort()
|
||
|
||
# 2. 实例化 WocBridgeClient 与 LifecycleHandler
|
||
# 依赖关系为单向:handler 在 onInit 调 client.attach_http_client 注入
|
||
# HTTP 连接池,client 不引用 handler。先创建 client,再创建 handler
|
||
# 并通过构造器注入。config_schema 取自 manifest(F-03 单真相源)。
|
||
client = WocBridgeClient(
|
||
config_port,
|
||
cache_port,
|
||
logger_port,
|
||
plugin_version=manifest.version,
|
||
)
|
||
handler = WeChatWocLifecycleHandler(
|
||
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 DEFAULT_MAX_CONNECTIONS
|
||
),
|
||
)
|
||
|
||
# 3. 注册 13 个适配器(12 必选 + 1 可选 directory)
|
||
# puller/outbound 接收 (client, config_port, logger_port);
|
||
# stream_connector/inbound/doctor/wizard/directory/login 接收
|
||
# (client, logger_port);lifecycle/whitelist 接收
|
||
# (cache_port, logger_port);probeable 接收
|
||
# (client, persistence_port, logger_port);session/status 无状态。
|
||
host.registerAdapter("puller", WeChatWocPullerAdapter(client, config_port, logger_port))
|
||
host.registerAdapter("stream_connector", WeChatWocStreamConnectorAdapter(client, config_port, logger_port))
|
||
host.registerAdapter("inbound", WeChatWocInboundAdapter(client, logger_port))
|
||
host.registerAdapter("outbound", WeChatWocOutboundAdapter(client, config_port, logger_port))
|
||
host.registerAdapter("session", WeChatWocSessionAdapter())
|
||
host.registerAdapter("status", WeChatWocStatusAdapter())
|
||
host.registerAdapter("login", WeChatWocLoginAdapter(client, logger_port))
|
||
host.registerAdapter("lifecycle", WeChatWocLifecycleAdapter(cache_port, logger_port))
|
||
host.registerAdapter("probeable", WeChatWocProbeableAdapter(client, persistence_port, logger_port))
|
||
host.registerAdapter("doctor", WeChatWocDoctorAdapter(client, logger_port))
|
||
host.registerAdapter("wizard", WeChatWocWizardAdapter(client, logger_port))
|
||
host.registerAdapter("whitelist", WeChatWocWhitelistAdapter(cache_port, logger_port))
|
||
host.registerAdapter("directory", WeChatWocDirectoryAdapter(client, logger_port))
|
||
|
||
# 4. 注册能力证明者(FR-08 增强)
|
||
# 对 manifest 声明的媒体出站能力进行运行时证明,避免 bridge 实际未
|
||
# 实现媒体发送时仍按声明能力调用(project_memory 硬约束)。
|
||
host.registerCapabilityProver(WocCapabilityProver(client))
|
||
|
||
# 5. 注册生命周期钩子
|
||
# PluginHost Protocol 未声明 registerLifecycleHandler,但 PluginHostImpl
|
||
# 已实现,运行时通过鸭子类型调用。
|
||
host.registerLifecycleHandler(handler)
|
||
|
||
# 6. 返回 PluginManifest(manifest 直接复用入参,adapters 为运行时清单)
|
||
return PluginManifest(
|
||
manifest=manifest,
|
||
adapters=_ADAPTER_TYPES,
|
||
)
|
||
|
||
|
||
CHANNEL_ENTRY = channel_entry
|