def connect_to_chat(self, name):
        connect_chat_request = MessageMapper.pack_connect_request(
            name, LISTENER_SOCKET_HOST,
            self.listener_socket.getsockname()[1])

        try:
            self.send(self.socket, connect_chat_request)

            connection_response: bytes = self.socket.recv(
                MAX_MESSAGE_SIZE_RECV)
            status: int = MessageMapper.unpack_status(connection_response[8:9])

            if status == Status.OK.value:
                global my_name
                my_name = name.lower()
                return (True, '')

            else:
                message = connection_response[9:]
                error_message = MessageMapper.unpack_error_response(message)
                return (False, error_message)

        except (ConnectionAbortedError, ConnectionResetError) as error:
            error_message = 'Connection reset.\nOS error: {0}'.format(error)
            self.disconnect_from_user(name)
            return (False, error_message)

        except OSError as error:
            error_message = 'Failed to send message to server. Try again.\nOS error: {0}'.format(
                error)
            return (False, error_message)
    def handle_validate_message(self, client_sock, message):
        status = MessageMapper.unpack_status(message)

        if status != Status.OK.value:
            self.close_connection(client_sock)
        else:
            print('User still active')
    def get_user_list(self):
        get_list_request = MessageMapper.pack_get_list_request()
        try:
            self.send(self.socket, get_list_request)
            get_list_response = self.socket.recv(MAX_MESSAGE_SIZE_RECV)
            user_list = MessageMapper.unpack_get_list_response(
                get_list_response[9:])
            return (True, user_list, None)

        except (ConnectionResetError, ConnectionAbortedError):
            error_message = 'Server disconnected'
            self.disconnect_from_chat()
            return (False, None, error_message)

        except OSError as error:
            message = 'OS error: {0}'.format(error) + ', try again'
            return (False, None, message)
    def handle_validation(self, socket):
        response = MessageMapper.pack_ok_response(
            Method.VALIDATE_CONNECTION.value)
        try:
            self.send(socket, response)

        except OSError:
            raise
 def validate_connection(self, name):
     validation: bytes = MessageMapper.pack_validate_user_message()
     socket = connections_lister.get_connection_by_name(name)
     if socket:
         try:
             socket.sendall(validation)
         except OSError:
             self.close_connection(socket)
    def connect_with_user(self, name):
        if name == my_name:
            error_message = 'You can\'t connect to yourself, try another user :)'
            return (False, error_message, None)

        else:
            if peers_lister.exists_in_peers(name):
                error_message = 'You are already connected to ' + name + ', try another user :)'
                return (False, error_message, None)

        get_user_request = MessageMapper.pack_get_user_request(name)

        try:
            self.send(self.socket, get_user_request)
            get_user_response = self.socket.recv(MAX_MESSAGE_SIZE_RECV)

            status = MessageMapper.unpack_status(get_user_response[8:9])
            message = get_user_response[9:]

            if status == Status.OK.value:
                user: User = MessageMapper.unpack_get_user_response(message)

                new_socket = sock.socket()
                success, message = self.connect(new_socket, user)
                if not success:
                    return (success, message, None)

                connections_lister.add_connection(user.name, new_socket)
                peers_lister.add_to_peers(user.name)

                return (True, None, new_socket)

            else:
                error_message = MessageMapper.unpack_error_response(message)
                return (False, error_message, None)

        except (ConnectionResetError, ConnectionAbortedError):
            error_message = 'Server disconnected'
            self.disconnect_from_chat()
            return (False, error_message, None)

        except OSError as error:
            error_message = 'Failed to send message\nOS error: {0}'.format(
                error) + '\nIf the error persists, consider disconnecting'
            return (False, error_message, None)
    def accept_connection(self, socket):
        try:
            (client_socket, address) = socket.accept()
            message = client_socket.recv(MAX_MESSAGE_SIZE_RECV)
            user_name = MessageMapper.unpack_user_id_on_connect_message(
                message[8:])
            return (client_socket, address, user_name)

        except OSError:
            raise
    def serve(self, client_sock, address):
        while True:
            try:
                request = client_sock.recv(MAX_MESSAGE_SIZE_RECV)

                if not request:
                    self.close_connection(client_sock, address)
                    return

                method = MessageMapper.unpack_method(request)
                message = request[8:]

                if method == Method.ENTER_CHAT.value:
                    user: User = MessageMapper.unpack_connect_request(message)
                    self.handle_connection_request(client_sock, user)

                elif method == Method.GET_USER.value:
                    user_name: str = MessageMapper.unpack_get_user_request(
                        message)
                    self.handle_get_user_request(client_sock, user_name)

                elif method == Method.CHECK_USER_CONNECTION.value:
                    user_name: str = MessageMapper.unpack_check_user_request(
                        message)
                    self.handle_check_request(user_name)

                elif method == Method.LIST_USERS.value:
                    self.handle_get_list_request(client_sock)

                elif method == Method.VALIDATE_CONNECTION.value:
                    self.handle_validate_message(client_sock, message)

            except (ConnectionAbortedError, ConnectionResetError):
                self.close_connection(client_sock, address)

            except OSError as error:
                print('OS error: {0}'.format(error))
    def handle_server_message(self):
        try:
            message = self.socket.recv(MAX_MESSAGE_SIZE_RECV)
            method = MessageMapper.unpack_method(message)
            if method == Method.VALIDATE_CONNECTION.value:
                self.handle_validation(self.socket)
                return (True, None)

        except (ConnectionResetError, ConnectionAbortedError):
            error_message = 'Server disconnected'
            self.disconnect_from_chat()
            return (False, error_message)

        except OSError as error:
            message = 'OS error: {0}'.format(error) + ', try again'
            return (False, message)
    def receive(self, client_sock):
        try:
            message = client_sock.recv(MAX_MESSAGE_SIZE_RECV)

            if not message:
                name = connections_lister.pop_connection_by_socket(
                    client_sock)[0]
                if name:
                    peers_lister.remove_from_peers(name)
                    message = name + ' disconnected'
                    return (False, message, None, client_sock)

            (user, msg) = MessageMapper.unpack_message_receive(message)
            return (True, msg, user, None)

        except (ConnectionAbortedError, ConnectionResetError) as error:
            error_message = 'Connection reset.\nOS error: {0}'.format(error)
            name = connections_lister.pop_connection_by_socket(client_sock)[0]
            if name:
                peers_lister.remove_from_peers(name)
                message = error_message + '\n' + name + ' disconnected'
                return (False, message, None, client_sock)
    def connect(self, socket, user: User):
        try:
            socket.connect((user.ip_address, user.port))

        except OSError as error:
            error_message = 'Failed to connect to ' + user.name + '\nOS error: {0}'.format(
                error)
            self.disconnect_from_user(user.name)
            self.check_user(user.name)
            return (False, error_message)

        id_msg = MessageMapper.pack_user_id_on_connect_message(my_name)

        try:
            self.send(socket, id_msg)
            return (True, None)

        except OSError as error:
            error_message = 'Failed to connect to ' + user.name + '\nOS error: {0}'.format(
                error)
            self.disconnect_from_user(user.name)
            self.check_user(user.name)
            return (False, error_message)
    def send_input_message_to_user(self, name, user_input):
        if name == my_name:
            error_message = 'You can\'t send a message to yourself, try someone else in the chat :)'
            return (False, error_message)

        else:
            if not peers_lister.exists_in_peers(name):
                error_message = 'You are not connected to' + name + '\nYou can\'t send a message to a user you are not connected to.'
                return (False, error_message)

        message = MessageMapper.pack_message_send(my_name, user_input)
        client_socket = connections_lister.get_connection_by_name(name)

        try:
            self.send(client_socket, message)
            return (True, '')

        except OSError as error:
            error_message = 'Failed to send message to ' + name + '\nOS error: {0}'.format(
                error
            ) + '\nIf the error persists, consider disconnecting from user'
            self.check_user(name)
            return (False, error_message)
 def check_user(self, name):
     check_user_request = MessageMapper.pack_check_user_request(name)
     self.send(self.socket, check_user_request)
 def send_list_response(self, client_sock, simplified_list):
     message = MessageMapper.pack_get_list_response(simplified_list)
     client_sock.sendall(message)
 def send_get_user_response(self, client_sock, user, request_type):
     user_response = MessageMapper.pack_get_user_response(
         user.name, user.ip_address, user.port)
     client_sock.sendall(user_response)
 def send_ok_response(self, client_sock, request_type):
     ok_response = MessageMapper.pack_ok_response(request_type)
     client_sock.sendall(ok_response)
 def send_error_response(self, client_sock, request_type, error_message):
     error_response = MessageMapper.pack_error_response(
         request_type, error_message)
     client_sock.sendall(error_response)