import asyncio import collections import logging import signal import sys class Client: def __init__(self, host='localhost', port=3001, buffer_chunk_size=10**4, buffer_length_limit=10**4): self._host = host self._port = port self._stopping = False self.buffer = collections.deque() # Shared queue of bytes self._buffer_chunk_size = buffer_chunk_size # How many bytes per chunk self._buffer_length_limit = buffer_length_limit # How many chunks in buffer self._file_path = None self._working = False @property def host(self) -> str: return self._host @property def port(self) -> int: return self._port @property def stopping(self) -> bool: return self._stopping @property def buffer_length_limit(self) -> int: return self._buffer_length_limit @property def buffer_chunk_size(self) -> int: return self._buffer_chunk_size @property def file_path(self) -> str: return self._file_path @property def working(self) -> bool: return self._working async def run_sending_client(self, file_path='~/output.txt'): self._file_path = file_path _, writer = await asyncio.open_connection(host=self.host, port=self.port) await self.send(writer=writer) async def send(self, writer: asyncio.StreamWriter): self._working = True with open(self.file_path, 'rb') as file_to_send: while not self.stopping: output_data = file_to_send.read(self.buffer_chunk_size) writer.write(output_data) await writer.drain() async def run_receiving_client(self, file_path='~/input.txt'): self._file_path = file_path reader, _ = await asyncio.open_connection(host=self.host, port=self.port) await self.receive(reader=reader) async def receive(self, reader: asyncio.StreamReader): self._working = True with open(self.file_path, 'wb') as file_to_receive: while not self.stopping: try: input_data = await reader.readexactly(self.buffer_chunk_size) except asyncio.IncompleteReadError as e: input_data = e.partial file_to_receive.write(input_data) def stop(self, *_): if self.working: logging.info("Received interruption signal, stopping...") self._stopping = True else: raise KeyboardInterrupt("Not working yet...") if __name__ == '__main__': log_formatter = logging.Formatter( "%(asctime)s [%(module)-15s %(levelname)-8s] %(message)s", style='%' ) root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) console_handler = logging.StreamHandler() console_handler.setFormatter(log_formatter) console_handler.setLevel(logging.DEBUG) root_logger.addHandler(console_handler) if len(sys.argv) > 1: action = sys.argv[1] else: action = input("Do you want to (R)eceive or (S)end a file?\t\t") action = ( 'send' if action.lower() == 's' else 'receive' ) if len(sys.argv) > 2: file_path = sys.argv[2] else: file_path = input(f"Enter file to {action}:\t\t\t\t\t\t") loop = asyncio.get_event_loop() client = Client( host='127.0.0.1', port=5000, ) loop.add_signal_handler(signal.SIGINT, client.stop, loop) logging.info("Starting client...") if action.lower() == 'send': loop.run_until_complete(client.run_sending_client(file_path=file_path)) else: loop.run_until_complete(client.run_receiving_client(file_path=file_path)) loop.close() logging.info("Stopped server")