def run(self): """ Method for starting the process of receiving messages from the server. :return: """ LOGGER.debug('Запущен процесс - приёмник сообщений с сервера.') while self.running: # If you do not delay, sending can wait a long time until the socket is released. time.sleep(1) message = None with SOCK_LOCK: try: self.client_sock.settimeout(0.5) message = get_message(self.client_sock) except OSError as err: if err.errno: LOGGER.critical('Потеряно соединение с сервером.') self.running = False self.connection_loss.emit() except (ConnectionError, ConnectionResetError, ConnectionAbortedError, TypeError, JSONDecodeError): LOGGER.critical('Потеряно соединение с сервером.') self.running = False self.connection_loss.emit() finally: self.client_sock.settimeout(5) if message: LOGGER.debug(f'Принято сообщение с сервера: {message}') self.receive_message(message)
def remove_contact_to_server(self, contact): """ The function sends contact deletion information to the server. :param {str} contact: username to remove from the contact list. :return: """ LOGGER.debug(f'Удаление контакта {contact}.') del_contact_dict = DEL_CONTACT_DICT del_contact_dict[USER] = self.username del_contact_dict[ACCOUNT_NAME] = contact # Send a message to the server. with SOCK_LOCK: send_message(self.client_sock, del_contact_dict) # Get a response from the server. self.receive_message(get_message(self.client_sock))
def add_contact_to_server(self, contact): """ The method sends information about adding a contact to the server. :param {str} contact: username to add to your contact list. :return: """ LOGGER.debug(f'Создание контакта {contact}.') add_contact_dict = ADD_CONTACT_DICT add_contact_dict[USER] = self.username add_contact_dict[ACCOUNT_NAME] = contact # Send a message to the server. with SOCK_LOCK: send_message(self.client_sock, add_contact_dict) # Get a response from the server. self.receive_message(get_message(self.client_sock))
def get_key_from_server(self, username): """ The method requests the public key from the server. :param {str} username: username. :return: """ LOGGER.debug(f'Запрос публичного ключа для {username}.') dict_message = GET_PUBLIC_KEY dict_message[USER] = username with SOCK_LOCK: send_message(self.client_sock, dict_message) server_answer = get_message(self.client_sock) if RESPONSE in server_answer and server_answer[RESPONSE] == 511 \ and DATA in server_answer: return server_answer[DATA] LOGGER.error(f'Не удалось получить ключ собеседника{username}.')
def create_message(self, recipient, message): """ Method for sending a message to the server. :param {obj} recipient: socket object. :param {str} message: message to the recipient. :return: """ dict_message = DICT_MESSAGE dict_message[SENDER] = self.username dict_message[RECIPIENT] = recipient dict_message[MESSAGE_TEXT] = message LOGGER.debug(f'Сформирован словарь-сообщение: {dict_message}.') # Send a message to the server. with SOCK_LOCK: send_message(self.client_sock, dict_message) self.receive_message(get_message(self.client_sock)) LOGGER.info(f'Сообщение отправлено пользователю {recipient}.')
def get_registered_user_from_server(self): """ The method requests from the server a list of registered users. :return {list}: list of registered users. """ LOGGER.debug(f'Запрос зарегистрированных пользователей {self.username}.') get_registered_dict = GET_REGISTERED_DICT get_registered_dict[USER] = self.username # Send a message to the server. LOGGER.debug(f'Сформирован запрос {get_registered_dict}.') with SOCK_LOCK: send_message(self.client_sock, get_registered_dict) # Get a response from the server. server_answer = get_message(self.client_sock) LOGGER.debug(f'Получен ответ {server_answer}.') if RESPONSE in server_answer and server_answer[RESPONSE] == 202 \ and DATA in server_answer: self.database.add_register_users(server_answer[DATA]) return server_answer[DATA] else: LOGGER.error('Не удалось обновить список известных пользователей.')
def get_contact_list_from_server(self): """ The method requests a list of user contacts from the server. :return {list}: user contact list. """ self.database.clear_contacts() LOGGER.debug(f'Запрос списка контактов пользователя {self.username}.') get_contacts_dict = GET_CONTACTS_DICT get_contacts_dict[USER] = self.username LOGGER.debug(f'Сформирован запрос {get_contacts_dict}.') # Send a message to the server. with SOCK_LOCK: send_message(self.client_sock, get_contacts_dict) # Get a response from the server. server_answer = get_message(self.client_sock) LOGGER.debug(f'Получен ответ {server_answer}.') if RESPONSE in server_answer and server_answer[RESPONSE] == 202 \ and DATA in server_answer: for contact in server_answer[DATA]: self.database.add_contact(contact) else: LOGGER.error('Не удалось обновить список контактов.')
def connection_init(self, ip_address, port): """ The method initiates a connection to the server. :param {str} ip_address: server IP-address. :param {int} port: server port :return: """ # Create a socket (AF_INET - network socket, SOCK_STREAM - work with TCP packets). self.client_sock = socket(AF_INET, SOCK_STREAM) # A timeout is required to free the socket. self.client_sock.settimeout(5) # Connect, 5 connection attempts, set success flag to True if possible. connected = False for attempt in range(5): LOGGER.info(f'Попытка подключения №{attempt + 1}.') try: self.client_sock.connect((ip_address, port)) except (OSError, ConnectionRefusedError): pass else: connected = True break time.sleep(1) # If connection failed, return an exception. if not connected: LOGGER.critical('Не удалось установить соединение с сервером.') raise ServerError('Не удалось установить соединение с сервером.') LOGGER.info(f'Установлено соединение с сервером {ip_address}:{port}.') # Start Authorization Procedure. # Get password hash. password_bytes = self.password.encode(ENCODING) salt = self.username.lower().encode(ENCODING) password_hash = pbkdf2_hmac('sha512', password_bytes, salt, 10000) password_hash_string = hexlify(password_hash) # Get the public key and decode it from bytes. public_key = self.keys.publickey().export_key().decode('ascii') # Authorization on the server. with SOCK_LOCK: presence_dict = CONFIRM_PRESENCE presence_dict[USER] = self.username presence_dict[PUBLIC_KEY] = public_key # Send server confirmation of presence. try: send_message(self.client_sock, presence_dict) server_answer = get_message(self.client_sock) if RESPONSE in server_answer: if server_answer[RESPONSE] == 400 and ERROR in server_answer: LOGGER.error(f'Сервер не смог обработать клиентский' f' запрос. Получен ответ "Response 400:' f' {server_answer[ERROR]}".') raise ServerError(server_answer[ERROR]) elif server_answer[RESPONSE] == 511 and DATA in server_answer: answer_data = server_answer[DATA] answer_hash = hmac.new( password_hash_string, answer_data.encode(ENCODING) ) hash_digest = answer_hash.digest() client_answer = RESPONSE_511 client_answer[DATA] = b2a_base64(hash_digest).decode('ascii') send_message(self.client_sock, client_answer) self.receive_message(get_message(self.client_sock)) except (OSError, JSONDecodeError): LOGGER.critical('Потеряно соединение с сервером.') raise ServerError('Потеряно соединение с сервером.')