move the original python code to legacy subdirectory
This commit is contained in:
		
							
								
								
									
										112
									
								
								legacy/server.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								legacy/server.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| from typing import Dict | ||||
|  | ||||
| import cv2 | ||||
| import socket | ||||
| import numpy as np | ||||
| from datetime import datetime | ||||
| import asyncio | ||||
| import asyncudp | ||||
| import argparse | ||||
| from rich.console import Console | ||||
|  | ||||
| from common import Packet, DoublyInterlacedPacket, from_bytes_dint | ||||
|  | ||||
| class Client: | ||||
|     """Class for tracking client state, including current frame data and time since last update.""" | ||||
|     def __init__(self): | ||||
|         self.last_updated = datetime.now() | ||||
|         self.frame = np.ndarray((HEIGHT, WIDTH, 3), dtype=np.uint8) | ||||
|  | ||||
|     def update(self, pkt: Packet): | ||||
|         """Apply a packet to the client frame. Update last client update to current time.""" | ||||
|         self.frame = pkt.apply(self.frame) | ||||
|  | ||||
|         self.last_updated = datetime.now() | ||||
|  | ||||
|     def latency(self) -> float: | ||||
|         """Return the time since the last client update.""" | ||||
|         return (datetime.now() - self.last_updated).total_seconds() | ||||
|  | ||||
|     def read(self) -> np.ndarray: | ||||
|         """Return the current frame.""" | ||||
|         return self.frame | ||||
|  | ||||
|  | ||||
| # Dictionary of client states stored by UUID | ||||
| frames: Dict[str, Client] = {} | ||||
|  | ||||
| async def show_frames(): | ||||
|     """Asynchronous coroutine to display frames in OpenCV debug windows.""" | ||||
|     while True: | ||||
|         # drop clients that have not sent packets for > 5 seconds | ||||
|         for id in list(frames.keys()): | ||||
|             if frames[id].latency() >= 5: | ||||
|                 console.log(f"Client likely lost connection, dropping [bold red]{id}[/bold red]") | ||||
|                 cv2.destroyWindow(id) | ||||
|                 frames.pop(id) | ||||
|             else: | ||||
|                 # show the latest available frame | ||||
|                 cv2.imshow(id, frames[id].read()) | ||||
|  | ||||
|         cv2.waitKey(1) | ||||
|         # this is necessary to allow asyncio to swap between reading packets and rendering frames | ||||
|         await asyncio.sleep(0.05) | ||||
|  | ||||
| async def listen(ip: str, port: int): | ||||
|     """Asynchronous coroutine to listen for / read client connections.""" | ||||
|     sock = await asyncudp.create_socket(local_addr=(ip, port)) | ||||
|  | ||||
|     console.log("Ready to accept connections.", style="bold green") | ||||
|  | ||||
|     while True: | ||||
|         # receive packets | ||||
|         data, addr = await sock.recvfrom() | ||||
|  | ||||
|         if data: | ||||
|             # convert the byte string into a packet object | ||||
|             pkt = from_bytes_dint(data) | ||||
|  | ||||
|             uuid = str(pkt.uuid) | ||||
|  | ||||
|             # if this is a new client, give it a new image | ||||
|             if uuid not in frames.keys(): | ||||
|                 console.log(f"New client acquired, naming [bold cyan]{uuid}[bold cyan]") | ||||
|                 frames[uuid] = Client() | ||||
|  | ||||
|             frames[uuid].update(pkt) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     # argument parser | ||||
|     parser = argparse.ArgumentParser(description="Proof-of-concept server for sauron-cv") | ||||
|     parser.add_argument("-p", "--port", type=int, default=5005) | ||||
|     parser.add_argument("-l", "--listen", type=str, default="0.0.0.0") | ||||
|     parser.add_argument("-W", "--width", type=int, default=640) | ||||
|     parser.add_argument("-H", "--height", type=int, default=480) | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # console | ||||
|     console = Console() | ||||
|  | ||||
|     # assign constants based on argument parser | ||||
|     UDP_IP = args.listen | ||||
|     UDP_PORT = args.port | ||||
|  | ||||
|     HEIGHT = args.height | ||||
|     WIDTH = args.width | ||||
|  | ||||
|     # create the async event loop | ||||
|     loop = asyncio.new_event_loop() | ||||
|     asyncio.set_event_loop(loop) | ||||
|  | ||||
|     # create async tasks for reading network packets, displaying windows | ||||
|     loop.create_task(listen(UDP_IP, UDP_PORT)) | ||||
|     loop.create_task(show_frames()) | ||||
|     try: | ||||
|         loop.run_forever() | ||||
|     finally: | ||||
|         loop.run_until_complete(loop.shutdown_asyncgens()) | ||||
|         loop.close() | ||||
|  | ||||
|         # Release the capture and close all windows | ||||
|         cv2.destroyAllWindows() | ||||
		Reference in New Issue
	
	Block a user