async def write_tcp_connection( host: str, port: int, token: str, sending_queue: asyncio.Queue, status_queue: asyncio.Queue, watchdog_queue: asyncio.Queue ) -> None: async with manage_status(status_queue, gui.SendingConnectionStateChanged): async with open_connection(host, port) as connection: reader, writer = connection watchdog_queue.put_nowait('Prompt before auth') recieved_data = await authorise(token, writer, reader) watchdog_queue.put_nowait('Authorization done') if not recieved_data: raise InvalidToken('Проверьте токен, сервер его не узнал.') await reader.readuntil(b'\n') event = gui.NicknameReceived(recieved_data['nickname']) status_queue.put_nowait(event) while True: message = await sending_queue.get() await submit_message(writer, message) watchdog_queue.put_nowait('Message sent')
async def handle_connection(host, reader_port, writer_port, history, token, queues): while True: try: async with mc.get_connection(host, writer_port, history, queues) as streams: async with timeout(CONNECTION_TIMEOUT): is_authorized, account_info = await mc.authorise( *streams, token) if not is_authorized: messagebox.showerror( 'Неизвестный токен', 'Проверьте токен или зарегистрируйте заново.') raise InvalidToken event = gui.NicknameReceived(account_info['nickname']) queues['status_updates_queue'].put_nowait(event) async with utils.create_handy_nursery() as nursery: nursery.start_soon( mc.restore_history(history, queues['messages_queue'])) nursery.start_soon( read_msgs(host, reader_port, history, queues)) nursery.start_soon(send_msgs(*streams, queues)) nursery.start_soon( watch_for_connection(queues["watchdog_queue"])) nursery.start_soon( ping_pong(*streams, queues["watchdog_queue"])) except (ConnectionRefusedError, ConnectionResetError, ConnectionError, asyncio.TimeoutError): continue else: break
async def send_msgs(host: str, port: int, token: Token, sending_queue: asyncio.Queue, status_queue: asyncio.Queue, watchdog_queue: asyncio.Queue) -> None: authorized = False async with connect( host=host, port=port, status_queue=status_queue, connect_state_mode=gui.SendingConnectionStateChanged) as (reader, writer): if not token.is_exist: status_queue.put_nowait(gui.SendingConnectionStateChanged.CLOSED) token.value, user = await registration(reader, writer) status_queue.put_nowait( gui.SendingConnectionStateChanged.INITIATED) authorized = True await watchdog_queue.put(WatchdogSwitcher.ENABLE) if not authorized: await watchdog_queue.put("Prompt before auth") user = await authorise(reader, writer, token.value) await status_queue.put(gui.NicknameReceived(user)) await watchdog_queue.put("Authorization done") status_queue.put_nowait(gui.SendingConnectionStateChanged.ESTABLISHED) async with create_handy_nursery() as nursery: nursery.start_soon( send_message(writer=writer, sending_queue=sending_queue, watchdog_queue=watchdog_queue)) nursery.start_soon(ping_pong(reader, writer, watchdog_queue))
async def handle_connection(queues, account_hash): while True: queues['watchdog'].put_nowait('Connection is alive. Source: Prompt before auth') async with open_asyncio_connection(HOST, WRITE_PORT) as rw_descriptor: reader, writer = rw_descriptor await reader.readline() try: account_dict = await authorise(reader, writer, account_hash) except InvalidToken: messagebox.showinfo("Ошибка авторизации", "Проверьте токен, сервер его не узнал.") queues['watchdog'].put_nowait('Connection is alive. Source: Authorization done') queues['messages'].put_nowait('Выполнена авторизация. Пользователь {}.\n'.format(account_dict['nickname'])) loaded_messages = read_file(HISTORY_FILE) queues['messages'].put_nowait(loaded_messages) nickname = gui.NicknameReceived(account_dict['nickname']) queues['status_updates'].put_nowait(nickname) async with anyio.create_task_group() as tg: await tg.spawn(read_msgs, HOST, READ_PORT, queues) await tg.spawn(save_messages, HISTORY_FILE, queues['saving']) await tg.spawn(send_msgs, HOST, WRITE_PORT, queues, account_hash) await tg.spawn(watch_for_connection, queues['watchdog']) await tg.spawn(ping_pong, reader, writer)
async def handle_connection(host, ports, history, token, queues): read_port, write_port = ports while True: # infinite loop to reconnect when ConnectionError occurred try: async with get_connection(host, write_port, queues) as streams: # set timeout for authorise/register procedure async with timeout(WATCH_CONNECTION_TIMEOUT): token_is_valid, username = await authorise(*streams, token) if not token_is_valid: username = gui.msg_box( "Invalid token", "If you're registered user, please click " '"Cancel" and check your .env file.\nIf you are the' ' new one, enter yor name below and click "OK"', ) if username == "": main_logger.info("User left 'username' empty") messagebox.showinfo( "Invalid username", "You entered empty 'username'. This is not " "allowed. Program is going to terminate.", ) raise UserInterrupt() if username is None: main_logger.info("User canceled 'username' input") raise UserInterrupt() await register(*streams, username) # Show received username in GUI queues["statuses"].put_nowait(gui.NicknameReceived(username)) async with create_handy_nursery() as nursery: nursery.start_soon( read_messages(host, read_port, history, queues)) nursery.start_soon(send_messages(*streams, queues)) nursery.start_soon(watch_for_connection( queues["watchdog"])) nursery.start_soon(ping_pong(*streams, queues["watchdog"])) except ( ConnectionRefusedError, ConnectionResetError, ConnectionError, asyncio.TimeoutError, ): # allow auto reconnection when ConnectionError or TimeoutError continue else: break
async def authorise(connection, token, watchdog_queue, status_updates_queue): await readline(connection.reader, watchdog_queue, 'Prompt before auth') await submit_message(connection.writer, token, watchdog_queue, 'Authorization token sent') text = await readline(connection.reader, watchdog_queue, 'Authorization done') json_data = json.loads(text) if not json_data: raise InvalidToken nickname = json_data['nickname'] event = gui.NicknameReceived(nickname) status_updates_queue.put_nowait(event)
async def authorize_and_send_msgs(host, port, token, sending_queue, status_updates_queue, watchdog_queue, ping_interval): reader, writer, json_answer = await authorize(host, port, token, status_updates_queue, watchdog_queue) nickname_update = gui.NicknameReceived(json_answer['nickname']) status_updates_queue.put_nowait(nickname_update) sender_lock = asyncio.Lock() async with create_handy_nursery() as nursery: nursery.start_soon( send_msgs(reader, writer, sending_queue, watchdog_queue, sender_lock)) nursery.start_soon( ping(reader, writer, ping_interval, watchdog_queue, sender_lock))
async def start_chat_process(stream_for_read, stream_for_write, token): authorisation_data = await authorise(stream_for_write, token) if not authorisation_data: broadcast_logger.info(f'NOT AUTORIZED WITH TOKEN "{token}"') raise InvalidTokenError _, _, nickname = authorisation_data event = gui.NicknameReceived(nickname) for _history in await load_log_from_file('chat_logs'): async_queues["messages_queue"].put_nowait(_history.strip()) async_queues["status_updates_queue"].put_nowait(event) async_queues["watchdog_queue"].put_nowait(f"Connection is alive. Source: " f"Authorisation as {nickname}") async with create_handy_nursery() as nursery: nursery.start_soon(broadcast_chat(stream_for_read, stream_for_write)) nursery.start_soon(send_message(stream_for_write)) nursery.start_soon(save_history())
async def authorise(token, reader, writer, status_updates_queue: asyncio.Queue): logging.debug(decode_message(await reader.readline())) writer.write(f"{token}\n".encode()) await writer.drain() response = json.loads(await reader.readline()) if not response: logging.error("Unknown token. Check it, or register new user") return False logging.debug(response) nickname = response.get('nickname') if nickname: status_updates_queue.put_nowait( gui.NicknameReceived(response.get('nickname'))) logging.debug(f"Выполнена авторизация. Пользователь {nickname}.") return True
async def open_writer(host, port, token, sending_queue, status_updates_queue): while True: try: reader, writer = await asyncio.open_connection(host, port) status_updates_queue.put_nowait( gui.SendingConnectionStateChanged.ESTABLISHED) if await reader.readline(): if token: account_info = await authorize(reader, writer, token) status_updates_queue.put_nowait( gui.NicknameReceived(account_info['nickname'])) await send_msgs(writer, sending_queue) except (asyncio.TimeoutError, ConnectionRefusedError, socket.gaierror): status_updates_queue.put_nowait( gui.SendingConnectionStateChanged.INITIATED) continue finally: writer.close()
async def connect_to_receiver(host, port, status_updates_queue, user, token_file, token): logger = logging.getLogger('connect_to_receiver_logger') while True: try: reader, writer = await asyncio.open_connection(host=host, port=port) temp = await reader.readline() logger.debug(temp.decode("utf-8")) if not token: writer.write('\n'.encode()) nickname = await register(reader, writer, user, token_file) else: nickname = await authorise(reader, writer, token) status_updates_queue.put_nowait(gui.SendingConnectionStateChanged.ESTABLISHED) status_updates_queue.put_nowait(gui.NicknameReceived(nickname)) return writer except InvalidToken: logger.error('invalid token') messagebox.showinfo("Invalid token", "Please, check your token, or remove it, to get another one") raise
async def inner(host, port, account_hash, queue): status_queue = context[queues]['status_updates_queue'] status_queue.put_nowait(gui.ReadConnectionStateChanged.INITIATED) status_queue.put_nowait( gui.SendingConnectionStateChanged.INITIATED) async with open_socket(host, int(port)) as socket_connection: if need_autorise: sending_queue = context[queues]['sending_queue'] watchdog_queue = context[queues]['watchdog_queue'] user_name = await autorise(socket_connection, account_hash) sending_queue.put_nowait( f'Выполнена авторизация. Пользователь {user_name}.') status_queue.put_nowait(gui.NicknameReceived(user_name)) status_queue.put_nowait( gui.SendingConnectionStateChanged.ESTABLISHED) watchdog_queue.put_nowait('Authorization done') else: status_queue.put_nowait( gui.ReadConnectionStateChanged.ESTABLISHED) await handle_msgs(socket_connection, queue)
async def authorize_writer(token, reader, writer, status_updates_queue, watchdog_queue): """Proceed login dialog on server over reader, writer. And report statuses to status_updates_queue and watchdog_queue. """ line = await reader.readline() decoded_line = line.decode() logger.debug('> %r', line) if not decoded_line.startswith( 'Hello %username%! Enter your personal hash or leave it empty to create new account.\n'): raise utils.ProtocolError(f'wrong hello message {line!r}') watchdog_queue.put_nowait('Prompt before auth') token_message = f'{token}\n' logger.debug('< %r', token_message) writer.write(token_message.encode()) await writer.drain() line = await reader.readline() login_response_json = line.decode() logger.debug('> %r', line) if not login_response_json.startswith('{') or token not in login_response_json: raise utils.WrongToken(f'cant login {line!r}') login_response = json.loads(login_response_json) line = await reader.readline() decoded_line = line.decode() logger.debug('> %r', decoded_line) if not decoded_line.startswith('Welcome to chat! Post your message below. End it with an empty line.\n'): raise utils.ProtocolError(f'wrong welcome message {line!r}') if login_response: nickname = login_response.get('nickname') logger.debug('Выполнена авторизация. Пользователь %r.', nickname) status_updates_queue.put_nowait(gui.NicknameReceived(nickname)) watchdog_queue.put_nowait('Authorization done')
async def handle_connection(host, port_to_read, port_to_write, token, filepath, queues): while True: # Open new stream. async with get_stream(host, port_to_write, queues, gui.SendingConnectionStateChanged.CLOSED) as (reader, writer): queues['watchdog'].put_nowait('Connection is alive. Prompt before auth') # Authorization. nickname = await auth(reader, writer, token, queues) queues['statuses'].put_nowait(gui.NicknameReceived(nickname)) queues['messages'].put_nowait( 'WELCOME BACK {}!\nLoading chat history and connectiong to chat ' 'in {} seconds...\n'.format(nickname, DELAY_TO_LOAD_HISTORY)) await asyncio.sleep(DELAY_TO_LOAD_HISTORY) # Read chat history. async with AIOFile(filepath, 'a+') as afp: history = await afp.read() if history: queues['messages'].put_nowait('*** CHAT HISTORY\n{}***\n'.format(history)) # Run grandchildren tasks. async with create_handy_nursery() as nursery: nursery.start_soon(log_msgs(filepath, queues)) nursery.start_soon(read_msgs(host, port_to_read, queues)) nursery.start_soon(send_msgs(writer, queues)) nursery.start_soon(watch_for_connection(queues)) nursery.start_soon(ping_pong(reader, writer))