import os import queue import threading import pika import time from datetime import datetime from typing import List import numpy as np import cv2 # # add python path of src to sys.path # src_path = os.path.join(__file__, *(['..'] * 2)) # src_path = os.path.abspath(src_path) # sys.path.insert(0, src_path) from ..protos import aerial_pb2 as pb from ..utils.tools import write_ply # class Message(object): # def __init__(self,sender_id,sender_key,body,routing_key): # self.sender_id = sender_id # self.sender_key = sender_key # self.body = body # self.routing_key = routing_key class senderThread(threading.Thread): def __init__(self, MQparams: pika.ConnectionParameters, exchange_name: str, exchange_type:str, # routing_key:str, message_queue:queue.Queue, ): super().__init__() self.MQparams = MQparams self.exchange_name = exchange_name self.exchange_type = exchange_type # self.routing_key = routing_key self.message_queue = message_queue # connect to RabbitMQ self.is_stop = False self.connection = pika.BlockingConnection(self.MQparams) def stop(self): """stop the thread""" self.is_stop = True # self.connection.close() def run(self): while not self.is_stop: # declare a exchange channel = self.connection.channel() channel.exchange_declare(exchange=self.exchange_name, exchange_type=self.exchange_type) while True: try: if not self.message_queue.empty() and not self.is_stop: # decode the routing key and message body from tuple list message = self.message_queue.get() msg_routing_key = message[0] msg_body = message[1] # publish a PERSISTENT message channel.basic_publish( exchange = self.exchange_name, routing_key = msg_routing_key, body = msg_body, properties=pika.BasicProperties( delivery_mode=pika.spec.PERSISTENT_DELIVERY_MODE ) ) timestamp = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') caption = f"[x] {timestamp} | Sending message to [{msg_routing_key}]" print(caption) else: time.sleep(1) except Exception as e: print(e) break class receiverThread(threading.Thread): def __init__(self, MQparams: pika.ConnectionParameters, exchange_name: str, exchange_type:str, MQqueue_name:str, binding_keys:List[str], message_queue:queue.Queue, ): super().__init__() self.MQparams = MQparams self.exchange_name = exchange_name self.exchange_type = exchange_type self.MQqueue_name = MQqueue_name self.binding_keys = binding_keys self.message_queue = message_queue # connect to RabbitMQ self.is_stop = False self.connection = pika.BlockingConnection(self.MQparams) def stop(self): """stop the thread""" self.is_stop = True # self.connection.close() def run(self): while not self.is_stop: # declare a exchange channel = self.connection.channel() channel.exchange_declare(exchange=self.exchange_name, exchange_type=self.exchange_type) # declare the queue and bind it with keys channel.queue_declare(queue=self.MQqueue_name, durable=True) for binding_key in self.binding_keys: channel.queue_bind(exchange=self.exchange_name, queue=self.MQqueue_name, routing_key=binding_key) print(f"[*] Using [{binding_key}] bind [{self.MQqueue_name}] on [{self.exchange_name}]") # consume the message channel.basic_qos(prefetch_count=1) channel.basic_consume( queue=self.MQqueue_name, on_message_callback=self.callback ) channel.start_consuming() def callback(self,ch, method, properties, body): if self.is_stop: ch.close() self.message_queue.put(body) ch.basic_ack(delivery_tag = method.delivery_tag) class decodeThread(threading.Thread): def __init__(self, queue_list:List[queue.Queue], queue_tags:List[str], save_path:str): super().__init__() self.queue_list = queue_list self.queue_tags = queue_tags self.queue_num = 0 self.save_path = save_path self.is_stop = False assert len(self.queue_list) == len(self.queue_tags) def stop(self): """stop the thread""" self.is_stop = True def run(self) -> None: # creating a path for saving data time_tag = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') self.save_root_folder = os.path.join(self.save_path,time_tag) os.makedirs(self.save_root_folder) self.logsmsg_folder = os.path.join(self.save_root_folder,"LogsMsg") self.imagesmsg_folder = os.path.join(self.save_root_folder,"ImagesMsg") self.plysmsg_folder = os.path.join(self.save_root_folder,"PlysMsg") self.commandsmsg_folder = os.path.join(self.save_root_folder,"CommandsMsg") sub_folder_list = [self.logsmsg_folder,self.imagesmsg_folder, self.plysmsg_folder,self.commandsmsg_folder] for folder in sub_folder_list: os.mkdir(folder) print(f"[NOTICE] Creating folder: {folder}") # process the queue list self.queue_num = len(self.queue_list) while self.queue_num: i = 0 while True: # select a queue i_tag = i % self.queue_num queue = self.queue_list[i_tag] # make sure the queue is not empty while not queue.empty() and not self.is_stop: # decode the msg using cooresponding method queue_tag = self.queue_tags[i_tag] decode_method = self.decode_select(queue_tag) decode_method(queue) # next queue i += 1 def decode_select(self,queue_tags:str): route_dic = { "Logs":self.decode_LogsMsg, "Images":self.decode_ImagesMsg, "Plys":self.decode_PlysMsg, "Commands":self.decode_CommandsMsg } return route_dic[queue_tags] def decode_LogsMsg(self,queue): nums_limit = 10 count = 0 while not queue.empty() and count < nums_limit: # extracting the msg from queue msg = queue.get() msg_pb = pb.LogsMessage() msg_pb.ParseFromString(msg) # save the raw pb msg curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') raw_file_name = os.path.join(self.logsmsg_folder,f"{curr_time}.LogsMsg") with open(raw_file_name, 'wb') as file: file.write(msg) # process the msg msg_source = msg_pb.source msg_timestamp = msg_pb.timestamp msg_context = msg_pb.context # display the info to the console curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') print(f"[x] {curr_time}|(From {msg_source}): {msg_context}" ) # next msg count += 1 def decode_ImagesMsg(self,queue): while not queue.empty(): # extracting the msg from queue msg = queue.get() msg_pb = pb.ImagesMessage() msg_pb.ParseFromString(msg) # save the raw pb msg curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') raw_file_name = os.path.join(self.imagesmsg_folder,f"{curr_time}.ImagesMsg") with open(raw_file_name, 'wb') as file: file.write(msg) # process the msg msg_source = msg_pb.source msg_timestamp = msg_pb.timestamp # process the images id = 0 for image in msg_pb.Image: imagelegth = image.length image_byte = image.data # save the images if (image_byte is None) | (len(image_byte) != imagelegth ): pass else: filename = f"{msg_source}_{msg_timestamp}_image{id}.jpg" filepath = os.path.join(self.imagesmsg_folder,filename) with open(filepath, 'wb') as f: f.write(image_byte) # display the info to the console curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') print(f"[x] {curr_time}|(From {msg_source}): image{id} saved!" ) # next image item id += 1 def decode_PlysMsg(self,queue): while not queue.empty(): # extracting the msg from queue msg = queue.get() msg_pb = pb.PlysMessage() msg_pb.ParseFromString(msg) # save the raw pb msg curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') raw_file_name = os.path.join(self.plysmsg_folder,f"{curr_time}.PlysMsg") with open(raw_file_name, 'wb') as file: file.write(msg) # process the msg msg_source = msg_pb.source msg_timestamp = msg_pb.timestamp # process the muti ply data id = 0 for ply in msg_pb.Plydata: data_legth = ply.length data_byte = ply.data rows = ply.rows cols = ply.cols order = ply.order dt = ply.dtype # save the pointcloud array data if (data_byte is None) | (len(data_byte) != data_legth): pass else: # frame the bytes to array data_array = np.frombuffer(data_byte,dtype=dt) data_array = data_array.reshape(rows,cols,order=order) # save the data with .ply format filename = f"{msg_source}_{msg_timestamp}_pointcloud{id}" write_ply(data_array,self.plysmsg_folder,filename) # next ply item id += 1 def decode_CommandsMsg(self,queue): raise NotImplementedError("NOT IMPLEMENT!") def send_logs_tool(logs:List[str], logs_queue:queue.Queue, source:str, routing_key:str): for i, log in enumerate(logs): if log is not None: # constract a logs message logsMsg = pb.LogsMessage() logsMsg.source = source logsMsg.timestamp = f"{time.asctime()}" logsMsg.context = log # convert the proto object to string logsMsg_bytes = logsMsg.SerializeToString() # add logsmsg to queue logs_queue.put([routing_key,logsMsg_bytes]) def send_images_tool(images:List[np.array], images_queue:queue.Queue, source:str, routing_key:str): # constract a images message imagesMsg = pb.ImagesMessage() imagesMsg.source = source curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') imagesMsg.timestamp = curr_time for img in images: if img is not None: success,image_encoded = cv2.imencode(".jpg",img) if success: image_bytes = image_encoded.tobytes() image_length = len(image_bytes) # add the encoded image to msg image_item = imagesMsg.Image.add() image_item.length = image_length image_item.data = image_bytes # converting the pb image msg to bytes imageMsg_bytes = imagesMsg.SerializeToString() # add the imageMsg to the queue images_queue.put([routing_key,imageMsg_bytes]) def send_pointcloud_tool(pointclouds:queue.Queue, plys_queue:queue.Queue, source:str, routing_key:str): # constract a plys message plysMsg = pb.PlysMessage() plysMsg.source = source curr_time = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') plysMsg.timestamp = curr_time run =True while run: while not pointclouds.empty(): value = pointclouds.get() if value is not False: pointcloud = np.array(value) # get the attributes of the PointCloudItem rows = pointcloud.shape[0] cols = pointcloud.shape[1] order = "C" dtype = str(pointcloud.dtype) data = pointcloud.tobytes(order=order) length = len(data) # add the pointcloud to the msg item = plysMsg.Plydata.add() item.length = length item.rows = rows item.cols = cols item.order = order item.dtype = dtype item.data = data else: # converting the pb ply msg to bytes plysMsg_bytes = plysMsg.SerializeToString() # add the plysMsg to the queue plys_queue.put([routing_key,plysMsg_bytes]) # end the outer while loop and triminate this function run = False