183 lines
6.3 KiB
Python

import json
import logging
import paho.mqtt.client as mqtt
import threading
import queue
import time
# MQTT 代理地址和端口
broker = "8.137.54.85" # 公共 MQTT 代理(免费)
port = 1883 # MQTT 默认端口
# 主题
topic = "ai/tottle/uvmodule"
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# 创建消息队列
message_queue = queue.Queue()
# 全局消息队列(可选,如果多个客户端需要共享消息)
global_message_queue = queue.Queue()
# uv_message_queue = queue.Queue()
# 接收消息并做本地缓存
# message_receive_queue = queue.Queue()
# # 暂时考虑只存储最新一条消息
# message_receive_queue = None
class MQTTClient:
def __init__(self, broker, port, topic, use_global_queue=False):
self.broker = broker
self.port = port
self.topic = topic
self.client = mqtt.Client()
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message # 绑定消息回调
self.use_global_queue = use_global_queue # 是否使用全局队列
self.local_mess = None
self.local_message_queue = queue.Queue() if not use_global_queue else None # 本地队列
self.client.connect(broker, port)
self.client.loop_start() # 启动网络线程
def on_connect(self, client, userdata, flags, rc):
"""连接成功时自动订阅主题"""
if rc == 0:
print(f"[MQTT] 成功连接到代理 {self.broker}:{self.port}")
self.client.subscribe(self.topic)
else:
print(f"[MQTT] 连接失败,错误代码: {rc}")
def on_message(self, client, userdata, msg):
"""收到消息时的回调"""
try:
payload = msg.payload.decode("utf-8")
# message_data = {
# "topic": msg.topic,
# "payload": payload,
# "qos": msg.qos,
# "retain": msg.retain,
# "ts": int(time.time() * 1000) # 毫秒级时间戳
# }
# data = json.loads(payload) # 解析为字典
message_data = json.loads(payload) # 解析为字典
# if self.use_global_queue:
# global_message_queue.put(message_data) # 存入全局队列
# else:
# self.local_message_queue.put(message_data) # 存入本地队列
print(f"on_message {message_data}")
# 增加格式验证,非法格式不做录入
if (message_data is not None
and message_data["task_id"] is not None
and message_data["list_s3_url"] is not None
and message_data["list_func_id"] is not None): #接收ai-tottle 消息
global_message_queue.put(message_data) # 存入全局队列
# self.local_mess=message_data
# print(f"[MQTT 接收] 主题: {msg.topic}, 消息: {payload}")
except Exception as e:
print(f"[MQTT 错误] 消息处理失败: {e}")
def publish_message(self, message):
"""发布消息"""
self.client.publish(self.topic, message)
print(f"[MQTT 发送] 主题: {self.topic}, 消息: {message}")
def publish_uv_result(self,topic, message):
"""发布消息"""
self.client.publish(topic, message)
print(f"[MQTT 发送] 主题: {self.topic}, 消息: {message}")
def get_messages(self, timeout=1):
"""
获取消息(支持超时)
- 如果使用全局队列,从 global_message_queue 获取
- 否则从本地队列获取
"""
messages = None
# target_queue = global_message_queue if self.use_global_queue else self.local_message_queue
start_time = time.time()
while time.time() - start_time < timeout:
try:
msg = global_message_queue.get()
if msg:
messages =msg
except queue.Empty:
break
return messages
def close(self):
"""关闭连接"""
self.client.loop_stop()
self.client.disconnect()
print("[MQTT] 已断开连接")
# 生产者线程:将消息放入队列
def producer_thread():
# message_queue.put(mess)
for i in range(100):
message = f"Message {i}"
message_queue.put(message)
print(f"生产者线程:已将消息放入队列: {message}")
# time.sleep(1) # 模拟生产间隔
# 消费者线程:从队列中取出消息并发布
def consumer_thread(mqtt_client):
print("consumer_thread")
# while True:
# try:
# message = message_queue.get(timeout=1) # 设置超时以避免无限阻塞
# mqtt_client.publish_message(message)
# message_queue.task_done() # 标记任务完成
# except queue.Empty:
# print("消费者线程:队列为空,等待中...")
# time.sleep(3) # 避免频繁检查队列
if __name__ == "__main__":
# 初始化 MQTT 客户端
mqtt_client = MQTTClient(broker, port, topic)
while True:
try:
raw_message = global_message_queue.get() # 阻塞等待消息
if raw_message is None: # 终止信号
break
logger.debug(f"处理原始消息: {raw_message}")
try:
# 解析JSON消息
# task_data = json.loads(raw_message)
logger.info(f"收到新任务: {raw_message}")
print(f"收到新任务: {raw_message}")
# # 处理任务
# result = process_uv_task(task_data)
#
# # 发布结果
# if result:
# mqtt_manager.publish(MQTT_PUBLISH_TOPIC, result)
except json.JSONDecodeError:
logger.error("无效的JSON格式")
except Exception as e:
logger.error(f"消息处理过程中发生错误: {e}")
except KeyboardInterrupt:
logger.info("收到中断信号,停止消息处理...")
break
except Exception as e:
logger.error(f"消息处理循环发生未预期错误: {e}")
time.sleep(1) # 避免频繁错误导致CPU占用过高