base_agent/uas/comm/main.py

165 lines
7.5 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.

# -*- coding: utf-8 -*-
"""
通信中间件框架 - 完整使用示例
演示:工厂创建、发布、订阅、对比三种协议
"""
import asyncio
import logging
from adapters.dds_adapter import DDSAdapterComm
from adapters.kafka_adapter import KafkaAdapterComm
# ── 注册所有内置适配器 ─────────────────────────────────────────────
from adapters.redis_adapter import RedisAdapterComm
from uas.comm.factory import CommAdapterFactory
from uas.comm.message import Message, MessagePriority
CommAdapterFactory.register("redis", RedisAdapterComm)
CommAdapterFactory.register("kafka", KafkaAdapterComm)
CommAdapterFactory.register("dds", DDSAdapterComm)
# ── 日志配置 ──────────────────────────────────────────────────────
logging.basicConfig(
level = logging.INFO,
format = "%(asctime)s [%(levelname)s] %(name)s - %(message)s",
)
logger = logging.getLogger("main")
# ─────────────────────────────────────────────────────────────────
# 消息处理回调
# ─────────────────────────────────────────────────────────────────
async def on_aircraft_status(msg: Message):
logger.info(f"🛩️ 收到飞行状态 | {msg.topic} | {msg.payload}")
async def on_alert(msg: Message):
logger.warning(f"🚨 告警消息 | priority={msg.priority.name} | {msg.payload}")
def on_telemetry_sync(msg: Message):
"""同步处理器也被支持"""
logger.info(f"📡 遥测数据 (sync) | {msg.payload}")
# ─────────────────────────────────────────────────────────────────
# 示例 1Redis
# ─────────────────────────────────────────────────────────────────
async def demo_redis():
url = "redis://:mypassword@127.0.0.1:6379/0?socket_timeout=5"
logger.info(f"\n{''*55}\n Redis 示例 url={url}\n{''*55}")
async with CommAdapterFactory.create(url) as adapter:
# 订阅
await adapter.subscribe("aircraft/status", on_aircraft_status)
await adapter.subscribe("aircraft/alert", on_alert)
# 发布
await adapter.publish(Message(
topic = "aircraft/status",
payload = {"id": "F-22", "speed": 2414, "altitude": 15000},
))
await adapter.publish(Message(
topic = "aircraft/alert",
payload = {"code": "E001", "msg": "发动机温度过高"},
priority = MessagePriority.URGENT,
))
await asyncio.sleep(0.5) # 等待消息到达
# ─────────────────────────────────────────────────────────────────
# 示例 2Kafka
# ─────────────────────────────────────────────────────────────────
async def demo_kafka():
url = "kafka://broker:9092/flight-group?auto_offset_reset=earliest&acks=all"
logger.info(f"\n{''*55}\n Kafka 示例 url={url}\n{''*55}")
async with CommAdapterFactory.create(url) as adapter:
await adapter.subscribe("telemetry", on_telemetry_sync)
await adapter.publish(Message(
topic = "telemetry",
payload = {"aircraft": "J-20", "lat": 39.9, "lon": 116.4, "alt": 20000},
headers = {"source": "radar-01"},
))
await asyncio.sleep(1.0)
# ─────────────────────────────────────────────────────────────────
# 示例 3DDS
# ─────────────────────────────────────────────────────────────────
async def demo_dds():
url = "dds://0@localhost:7400/rt?reliability=RELIABLE&durability=TRANSIENT_LOCAL"
logger.info(f"\n{''*55}\n DDS 示例 url={url}\n{''*55}")
async with CommAdapterFactory.create(url) as adapter:
await adapter.subscribe("command/fire", on_alert)
await adapter.publish(Message(
topic = "command/fire",
payload = {"weapon": "AIM-120", "target": "T001"},
priority = MessagePriority.HIGH,
))
await asyncio.sleep(0.3)
# ─────────────────────────────────────────────────────────────────
# 示例 4扩展新协议MQTT
# ─────────────────────────────────────────────────────────────────
async def demo_extend_mqtt():
"""
演示如何在运行时注册新协议,无需修改框架代码
只需实现 CommBaseAdapter 子类并调用 register()
"""
from uas.comm.base import CommBaseAdapter, MessageHandler
from uas.comm.message import Message
class MqttAdapter(CommBaseAdapter):
"""MQTT 适配器骨架(实际使用 aiomqtt 库)"""
async def connect(self):
self._running = True
self.logger.info(f"[MQTT] 连接到 {self.config.host}:{self.config.port}")
async def disconnect(self):
self._running = False
async def publish(self, message: Message) -> bool:
self.logger.info(f"[MQTT] 发布 {message.topic}: {message.payload}")
return True
async def subscribe(self, topic: str, handler: MessageHandler):
self._register_handler(topic, handler)
self.logger.info(f"[MQTT] 订阅 {topic}")
async def unsubscribe(self, topic: str):
self._handlers.pop(topic, None)
# 动态注册
CommAdapterFactory.register("mqtt", MqttAdapter)
url = "mqtt://broker.hivemq.com:1883/aircraft?qos=1"
async with CommAdapterFactory.create(url) as adapter:
await adapter.subscribe("sensor/+/temp", on_telemetry_sync)
await adapter.publish(Message(
topic = "sensor/001/temp",
payload = {"temp": 85.3},
))
logger.info(f"当前已注册协议: {CommAdapterFactory.available_schemes()}")
# ─────────────────────────────────────────────────────────────────
# 主入口
# ─────────────────────────────────────────────────────────────────
async def main():
# 注意Redis/Kafka 需要真实服务DDS 在无 cyclonedds 时自动降级为模拟模式
# await demo_redis()
# await demo_kafka()
await demo_dds()
await demo_extend_mqtt()
if __name__ == "__main__":
asyncio.run(main())