WechatOnCloud/bridge/woc_bridge/ui/capabilities.py

127 lines
4.4 KiB
Python
Raw Normal View History

"""L6 Capability API对外能力接口SendResult + WeChatCapabilities
P1 阶段WeChatCapabilities.send_text 委托给旧 xdotool_driver.send_text
把返回的 local_send_id 包成 SendResult(success=True, verified=True)
P3 阶段替换为 FlowOrchestrator.send_text统一走状态机 + DB 校验 + 幂等
"""
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from typing import Optional
logger = logging.getLogger("woc-bridge")
@dataclass
class SendResult:
"""发送文本结果。
所有字段带默认值避免构造时必填字段顺序问题
diagnostics field(default=None) + Optional 避免可变默认值陷阱
Attributes:
success: 是否成功含校验通过
local_id: 本地生成的消息 ID local_<unix>_<rand>
verified: 是否经 DB 校验确认P1 阶段默认 TrueP3 接入真实校验
skipped: 是否因幂等命中而跳过实际发送
error: 错误描述成功时为空
error_code: 错误码 WINDOW_NOT_FOUND / SEND_TIMEOUT
retryable: 是否可安全重试
diagnostics: 诊断信息字典trace_id / image_confidence / duration_ms
"""
success: bool = False
local_id: str = ""
verified: bool = False
skipped: bool = False
error: str = ""
error_code: str = ""
retryable: bool = False
diagnostics: Optional[dict] = field(default=None)
class WeChatCapabilities:
"""L6 对外能力 API业务层路由 / outbox通过此类调用 UI 自动化。
P1 阶段xdotool_driver 非空orchestrator Nonesend_text 委托给
xdotool_driver.send_text包成 SendResult
P3 阶段orchestrator 非空xdotool_driver Nonesend_text 委托给
FlowOrchestrator.send_textTODO: P3 时统一走 orchestrator
"""
def __init__(self, xdotool_driver=None, orchestrator=None) -> None:
"""初始化能力 API。
Args:
xdotool_driver: XdotoolDriver 实例P1 阶段非空
orchestrator: P3 阶段的 FlowOrchestrator 实例P1 阶段为 None
"""
self.xdotool_driver = xdotool_driver
self.orchestrator = orchestrator
async def send_text(
self,
to_wxid: str,
content: str,
display_name: Optional[str] = None,
client_request_id: str = "",
) -> SendResult:
"""发送文本消息。
P1 阶段 orchestrator 非空则委托 orchestrator.send_text
否则调 xdotool_driver.send_text把返回的 local_send_id 包成
SendResult(success=True, local_id=..., verified=True)
TODO: P3 时统一走 orchestrator移除 xdotool_driver 分支
Args:
to_wxid: 目标 wxid
content: 文本内容
display_name: 用于搜索定位会话的显示名备注/昵称/微信号
client_request_id: 幂等键维度P1 阶段忽略P3 接入 IdemCache
Returns:
SendResult发送结果
"""
# TODO: P3 时统一走 orchestrator
if self.orchestrator is not None:
return await self.orchestrator.send_text(
to_wxid=to_wxid,
content=content,
display_name=display_name,
client_request_id=client_request_id,
)
# P1 阶段:委托给旧 xdotool_driver
if self.xdotool_driver is None:
return SendResult(
success=False,
error="no backend available (xdotool_driver and orchestrator both None)",
error_code="BRIDGE_NOT_INITIALIZED",
retryable=False,
)
try:
local_send_id = await self.xdotool_driver.send_text(
to_wxid=to_wxid,
content=content,
display_name=display_name,
)
return SendResult(
success=True,
local_id=str(local_send_id),
verified=True,
)
except Exception as exc:
logger.error(
"[capability] send_text failed to=%s: %s", to_wxid, exc
)
return SendResult(
success=False,
error=str(exc),
error_code="SEND_FAILED",
retryable=True,
)