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)