feat:初始化工程

This commit is contained in:
2025-10-27 19:05:54 +08:00
commit c85f481a18
11 changed files with 429 additions and 0 deletions

136
endpoint/mqtt_client.py Normal file
View File

@@ -0,0 +1,136 @@
import paho.mqtt.client as mqtt
import uuid
from config.logger_config import logger
from config.setting import settings
class MQTTClient:
def __init__(self):
self.broker_host = settings.mqtt_host
self.broker_port = settings.mqtt_port
self.client_id = self.generate_client_id()
self.client = mqtt.Client(client_id=self.client_id)
# 注册回调函数
self.client.on_connect = self._on_connect
self.client.on_disconnect = self._on_disconnect
self.client.on_message = self._on_message
# 存储消息处理器的字典,键为主题,值为处理函数
self.message_handlers = {}
self.connected = False
def _on_connect(self, client, userdata, flags, rc):
"""连接回调函数"""
self.connected = rc == 0
if self.connected:
logger.info(f"成功连接到MQTT broker {self.broker_host}:{self.broker_port}")
else:
logger.error(f"连接MQTT broker失败错误代码: {rc}")
def _on_disconnect(self, client, userdata, rc):
"""断开连接回调函数"""
self.connected = False
if rc != 0:
logger.warning(f"意外断开与MQTT broker的连接错误代码: {rc}")
else:
logger.info("已与MQTT broker断开连接")
def _on_message(self, client, userdata, msg):
"""消息接收回调函数"""
logger.info(f"收到消息: {msg.topic}")
try:
if msg.topic in self.message_handlers:
self.message_handlers[msg.topic](client, msg)
else:
logger.warning(f"未找到 {msg.topic} 的消息处理器")
except Exception as e:
logger.error(f"处理消息时出错: {str(e)}", exc_info=True)
@staticmethod
def generate_client_id(prefix: str = "client") -> str:
"""生成唯一客户端ID"""
uuid_str = str(uuid.uuid4()).split('-')[0]
return f"{prefix}-{uuid_str}"
def add_message_handler(self, topic, handler):
"""添加消息处理器"""
if topic in self.message_handlers:
logger.warning(f"主题 {topic} 已存在处理器,将被覆盖")
self.message_handlers[topic] = handler
logger.info(f"为主题 {topic} 注册了消息处理器")
logger.debug(f"当前消息处理器: {self.message_handlers.keys()}")
def connect(self):
"""连接到MQTT服务器"""
try:
self.client.connect(self.broker_host, self.broker_port)
self.start_loop()
return True
except Exception as e:
logger.error(f"连接MQTT broker {self.broker_host}:{self.broker_port}时发生错误: {str(e)}", exc_info=True)
return False
def disconnect(self):
"""断开与MQTT服务器的连接"""
try:
self.stop_loop()
self.client.disconnect()
logger.info("正在断开与MQTT broker的连接")
except Exception as e:
logger.error(f"断开连接时发生错误: {str(e)}", exc_info=True)
def subscribe(self, topic, qos=0):
"""订阅主题"""
try:
result, mid = self.client.subscribe(topic, qos)
if result == mqtt.MQTT_ERR_SUCCESS:
logger.info(f"已订阅主题: {topic} (QoS: {qos})")
return True
else:
logger.error(f"订阅主题 {topic} 失败,错误代码: {result}")
return False
except Exception as e:
logger.error(f"订阅主题时发生错误: {str(e)}", exc_info=True)
return False
def publish(self, topic, payload, qos=0, retain=False):
"""发布消息到指定主题"""
if not self.connected:
logger.warning("未连接到MQTT broker无法发布消息")
return False
try:
result = self.client.publish(topic, payload, qos, retain)
result.wait_for_publish()
if result.rc == mqtt.MQTT_ERR_SUCCESS:
logger.debug(f"已发布消息到主题 {topic}: {payload}")
return True
else:
logger.error(f"发布消息到主题 {topic} 失败,错误代码: {result.rc}")
return False
except Exception as e:
logger.error(f"发布消息时发生错误: {str(e)}", exc_info=True)
return False
def start_loop(self):
"""启动MQTT网络循环"""
try:
self.client.loop_start()
logger.info("已启动MQTT网络循环")
except Exception as e:
logger.error(f"启动网络循环时发生错误: {str(e)}", exc_info=True)
def stop_loop(self):
"""停止MQTT网络循环"""
try:
self.client.loop_stop()
logger.info("已停止MQTT网络循环")
except Exception as e:
logger.error(f"停止网络循环时发生错误: {str(e)}", exc_info=True)
mqtt_client = MQTTClient()

84
endpoint/tcp_server.py Normal file
View File

@@ -0,0 +1,84 @@
import asyncio
import signal
import platform
from config.logger_config import logger
from config.setting import settings
from model.index import UNKNOWN_MESSAGE
from processor.tcp_processor import TcpMessageProcessor
class TCPServer:
def __init__(self):
self.host = settings.tcp_host
self.port = settings.tcp_port
self.server = None
self.clients = set()
self.running = False
self.message_processor = TcpMessageProcessor()
async def handle_client(self, reader, writer):
"""处理客户端连接"""
addr = writer.get_extra_info('peername')
logger.info(f"新客户端连接: {addr}")
self.clients.add(writer)
try:
while self.running:
data = await reader.read(1024)
if not data:
break # 连接断开
message = data.decode('utf-8').strip()
logger.info(f"收到 {addr} 的消息: {message}")
# 放到消息处理器里面处理
response = self.message_processor.process(message)
# 回复消息
if response != UNKNOWN_MESSAGE:
writer.write(response.encode())
await writer.drain()
logger.info(f"回复 {addr}: {response}")
except Exception as e:
logger.error(f"客户端 {addr} 处理错误: {e}")
finally:
if writer in self.clients:
self.clients.remove(writer)
writer.close()
await writer.wait_closed()
logger.warning(f"客户端 {addr} 断开")
async def start(self):
"""启动服务器"""
self.running = True
self.server = await asyncio.start_server(self.handle_client, self.host, self.port)
# 仅在非Windows平台设置信号处理
if platform.system() != 'Windows':
loop = asyncio.get_running_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, self.stop)
logger.info(f"TCP服务器已启动 {self.host}:{self.port}")
async with self.server:
await self.server.serve_forever()
async def _safe_stop(self):
"""安全的停止服务器"""
self.running = False
if self.server:
self.server.close()
await self.server.wait_closed()
# 关闭所有客户端连接
for writer in list(self.clients):
writer.close()
await writer.wait_closed()
def stop(self):
"""停止服务器"""
logger.info("正在关闭TCP服务器...")
asyncio.create_task(self._safe_stop())
tcp_server = TCPServer()