diff --git a/README.MD b/README.MD index f2ec550..a1ab04b 100644 --- a/README.MD +++ b/README.MD @@ -23,11 +23,39 @@ import asyncio import cmd_chat if __name__ == '__main__': - asyncio.run( - cmd_chat.run() - ) + asyncio.run(cmd_chat.run()) ``` + +### Or (Windows) + +Start server: + +``` +.\cmd_chat.bat serve localhost 5000 +``` + +Connect to server: + +``` +.\cmd_chat.bat connect localhost 5000 tyler +``` + +### Or (Linux) + +Start server: + +``` +python3 cmd_chat.py serve localhost 5000 +``` + +Connect to server: + +``` +python3 cmd_chat.py connect localhost 5000 tyler +``` + + How does encryption work? * The client generates a private key. @@ -40,3 +68,8 @@ How does encryption work? # Example ![Alt Text](example.gif) + +# Known bugs + +* Sometime WS just drop connection +* Client input message problem. To start input, you need to press enter first, only after that you got pop up with message. Tried to fix, but nothing worked. diff --git a/cmd_chat.bat b/cmd_chat.bat new file mode 100644 index 0000000..09b529e --- /dev/null +++ b/cmd_chat.bat @@ -0,0 +1,2 @@ +@echo off +python cmd_chat.py %* \ No newline at end of file diff --git a/main.py b/cmd_chat.py similarity index 100% rename from main.py rename to cmd_chat.py diff --git a/cmd_chat/__init__.py b/cmd_chat/__init__.py index a6038d3..4d2eb07 100644 --- a/cmd_chat/__init__.py +++ b/cmd_chat/__init__.py @@ -1,4 +1,5 @@ import asyncio +import argparse from cmd_chat.server.server import app from cmd_chat.client.client import Client @@ -28,23 +29,36 @@ async def run_client( async def run() -> None: - action: int = int( - input("Choose action:\n1. Run server\n2. Run client\nAction: ") + parser = argparse.ArgumentParser( + description='Command-line chat application' ) - if action == 1: - await run_server( - input("IP: "), - int(input("PORT: ")) - ) - if action == 2: - await run_client( - input("USERNAME: "), - input("IP: "), - int(input("PORT: ")) - ) + parser.add_argument( + 'command', + choices=['serve', 'connect'], + help='Command to execute' + ) + parser.add_argument( + 'ip_address', + help='IP address to serve or connect' + ) + parser.add_argument( + 'port', + help='PORT of server' + ) + parser.add_argument( + 'username', + nargs='?', + default='', + help='Username for connection (required for connect command)' + ) + args = parser.parse_args() + if args.command == 'serve': + await run_server(args.ip_address, int(args.port)) + elif args.command == 'connect': + if not args.username: + parser.error("Username is required for 'connect' command") + await run_client(args.username, args.ip_address, int(args.port)) if __name__ == '__main__': - asyncio.run( - run() - ) \ No newline at end of file + asyncio.run(run()) \ No newline at end of file diff --git a/cmd_chat/client/client.py b/cmd_chat/client/client.py index af8bfe0..dd1781b 100644 --- a/cmd_chat/client/client.py +++ b/cmd_chat/client/client.py @@ -9,7 +9,8 @@ from websocket import create_connection from cmd_chat.client.core.crypto import RSAService from cmd_chat.client.config import ( - COLORS + COLORS, + RENDER_TIME ) @@ -109,13 +110,13 @@ class Client(RSAService): def update_info(self): """ connecting to websocket, wating for updates, - updating every 0.05 seconds + updating every RENDER_TIME seconds """ ws = create_connection(f"{self.ws_url}/update") last_try = None while True: try: - time.sleep(0.05) + time.sleep(RENDER_TIME) response = ast.literal_eval(ws.recv().decode('utf-8')) if last_try == response: continue diff --git a/cmd_chat/client/config.py b/cmd_chat/client/config.py index c12aa11..3493884 100644 --- a/cmd_chat/client/config.py +++ b/cmd_chat/client/config.py @@ -5,4 +5,6 @@ COLORS = { "my_username_color": Fore.MAGENTA, "ip_color": Fore.MAGENTA, "username_color": Fore.GREEN -} \ No newline at end of file +} + +RENDER_TIME = 0.05 \ No newline at end of file diff --git a/cmd_chat/server/services.py b/cmd_chat/server/services.py index 0b114a8..ec3280c 100644 --- a/cmd_chat/server/services.py +++ b/cmd_chat/server/services.py @@ -6,8 +6,7 @@ from cmd_chat.server.models import Message async def _get_bytes_and_serialize( ws: Websocket ) -> dict: - ws_data = await ws.recv() - return ast.literal_eval(ws_data.decode('utf-8')) + return ast.literal_eval(await ws.recv()) async def _check_ws_for_close_status(