# -*- coding: utf-8 -*- """ 通信适配器抽象基类 所有中间件适配器必须继承此类并实现全部抽象方法 遵循 Factory + Strategy 模式 """ import asyncio import logging from abc import ABC, abstractmethod from dataclasses import dataclass from typing import Callable, Awaitable, List, Optional from uas.comm.message import Message logger = logging.getLogger(__name__) # 消息处理器类型:同步 or 异步均可 MessageHandler = Callable[[Message], Optional[Awaitable[None]]] @dataclass class ConnectionConfig: """通用连接配置(由 URL 解析填充)""" scheme: str # redis / kafka / dds host: str = "localhost" port: int = 0 username: str = "" password: str = "" database: str = "" # redis db index / kafka group id / dds domain options: dict = None # URL query 参数 def __post_init__(self): if self.options is None: self.options = {} class CommBaseAdapter(ABC): """ 所有通信适配器的抽象基类 子类只需实现以下 5 个核心方法 """ def __init__(self, config: ConnectionConfig): self.config = config self.logger = logging.getLogger(self.__class__.__name__) self._running = False self._handlers: dict[str, List[MessageHandler]] = {} # ── 生命周期 ────────────────────────────────────────────────── @abstractmethod async def connect(self) -> None: """建立连接""" ... @abstractmethod async def disconnect(self) -> None: """断开连接""" ... @property def is_connected(self) -> bool: return self._running # ── 核心功能 ────────────────────────────────────────────────── @abstractmethod async def publish(self, message: Message) -> bool: """ 发布消息到指定 topic :return: True 表示发送成功 """ ... @abstractmethod async def subscribe(self, topic: str, handler: MessageHandler) -> None: """ 订阅 topic,注册消息处理回调 支持通配符(由各适配器自行实现) """ ... @abstractmethod async def unsubscribe(self, topic: str) -> None: """取消订阅""" ... # ── 可选扩展 ────────────────────────────────────────────────── async def request(self, message: Message, timeout: float = 5.0) -> Optional[Message]: """ Request/Reply 模式(默认未实现,子类可覆盖) """ raise NotImplementedError(f"{self.__class__.__name__} 不支持 Request/Reply 模式") async def health_check(self) -> bool: """健康检查,默认返回连接状态""" return self._running # ── 内部工具 ────────────────────────────────────────────────── def _register_handler(self, topic: str, handler: MessageHandler): self._handlers.setdefault(topic, []).append(handler) async def _dispatch(self, message: Message): """将消息分发给所有匹配的 handler""" handlers = self._handlers.get(message.topic, []) for handler in handlers: try: result = handler(message) if asyncio.iscoroutine(result): await result except Exception as e: self.logger.error(f"Handler 执行异常 topic={message.topic}: {e}", exc_info=True) async def __aenter__(self): await self.connect() return self async def __aexit__(self, *args): await self.disconnect()