ForcePilot/backend/package/yuxi/channels/plugins/wechat_woc/entry.py
Kris 977724d7c3 refactor(wechat-woc,transport): 批量代码优化与功能增强
1.  修复代码格式与缩进问题,统一代码风格
2.  调整凭证缓存TTL为不过期,显式管理缓存失效
3.  重构wechat-woc出站请求,添加可重入锁保证同账号串行调用
4.  新增wechat-woc向导适配器配置端口支持,兼容开发环境localhost
5.  实现入站消息出站投递异步化,添加账号级并发限制
6.  新增transport启动前凭证缓存预热逻辑
7.  调整导入顺序与依赖位置,优化代码结构
2026-07-11 05:42:26 +08:00

193 lines
9.8 KiB
Python
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_wocWechatOnCloud渠道插件入口。
实现 ``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
- ``wizard`` 接收 ``(client, config_port, logger_port, channel_type)``
需从 ConfigPort CHANNEL 作用域读取 ``allow_insecure_localhost`` 以兼容
开发环境 localhost http bridge_url。
- ``inbound`` / ``doctor`` / ``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``降级启动StreamWorker permanent 失败时(如 bridge
< 1.5.0 无 SSE 端点、SSE 端点鉴权失败),由 TransportManager 触发降级
启动,以短轮询 ``/api/messages/since``2s 间隔)接收消息。账号重新上线
时清除降级标记恢复 both 模式P0-1
两者由传输引擎通过 ``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 ._constants import DEFAULT_MAX_CONNECTIONS
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 .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/LoggerPortbridge_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 取自 manifestF-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, cache_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, config_port, logger_port, manifest.channel_type))
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. 返回 PluginManifestmanifest 直接复用入参adapters 为运行时清单)
return PluginManifest(
manifest=manifest,
adapters=_ADAPTER_TYPES,
)
CHANNEL_ENTRY = channel_entry