def main_loop(self): presence_msg = JimMessage(action=PRESENCE, time=time.time()) self.socket.send(bytes(presence_msg)) presence_response_bytes = self.socket.recv(1024) presence_response = JimResponse.create_from_bytes( presence_response_bytes) if presence_response.response == OK: print('Связь с сервером установлена') if self.mode == 'r': while True: message_bytes = self.socket.recv(1024) jimmsg = JimMessage.create_from_bytes(message_bytes) print( 'Вы получили от {} {} сообщеие'.format( self.socket.fileno(), self.socket.getpeername()), jimmsg.message) elif self.mode == 'w': while True: message = input('Пошлите сообщение в никуда =') msg = JimMessage(action=MSG, time=time.time(), encoding='utf-8', message=message) self.socket.send(bytes(msg)) else: raise WrongModeError(mode) elif presence_response.response == SERVER_ERROR: print('Ошибка сервера') elif presence_response.response == WRONG_REQUEST: print('Неверный запрос на сервер') else: print('Неверный код ответа от сервера')
def get_connection(self): try: conn, addr = self.socket.accept() presence_msg_bytes = conn.recv(1024) presence_msg = JimMessage.create_from_bytes(presence_msg_bytes) if presence_msg.action == PRESENCE: presence_response = JimResponse(**{RESPONSE: OK}) conn.send(bytes(presence_response)) else: presence_response = JimResponse(**{RESPONSE: WRONG_REQUEST}) conn.send(bytes(presence_response)) except OSError as e: pass else: print("Получен запрос на соединение от {}".format(str(addr))) self.clients.append(conn) finally: wait = 0 read = [] write = [] try: read, write, e = select.select(self.clients, self.clients, [], wait) except: pass requests = self.read_requests(read) self.write_responses(requests, write)
def read_requests(self, read_clients): all_messages = [] for sock in read_clients: try: bytemsg = sock.recv(1024) jimmsg = JimMessage.create_from_bytes(bytemsg) all_messages.append(jimmsg) except: print('Клиент {} {} отключился'.format(sock.fileno(), sock.getpeername())) self.clients.remove(sock) return all_messages
def send_message(self, to, text): # формируем сообщение message = JimMessage(**{ ACTION: MSG, TO: to, FROM: self.name, MESSAGE: text, TIME: time.time() }) # отправляем self.socket.send(bytes(message))
def send_presence(self): """Отправить сообщение о присутствии""" presence_msg = JimMessage(action=PRESENCE, time=time.time(), user={ACCOUNT_NAME: self.name}) # переводим в байты и отправляем self.socket.send(bytes(presence_msg)) # получаем ответ в байтах presence_response_bytes = self.socket.recv(1024) # создаем ответ из байт presence_response = JimResponse.create_from_bytes( presence_response_bytes) return presence_response
def del_contact(self, username): # формируем сообщение на добавления контакта message = JimMessage(action=DEL_CONATCT, user_id=username, time=time.time(), user=self.name) # отправляем сообщение на сервер self.socket.send(bytes(message)) # получаем ответ от сервера # получаем ответ из очереди # Формируем сообщение из байт jm = self.request_queue.get() if jm.response == OK: print('Контакт {} успешно удален'.format(username)) # удаляем контакт из своей базы self.repo.del_contact(username) self.repo.commit()
def add_contact(self, username): # формируем сообщение на добавления контакта add_message = JimMessage(action=ADD_CONTACT, user_id=username, time=time.time(), user=self.name) # отправляем сообщение на сервер self.socket.send(bytes(add_message)) # получаем ответ от сервера # ответ получает слушатель, мы его получаем через очередь jm = self.request_queue.get() # Формируем сообщение из байт if jm.response == OK: print('Новый контакт {} успешно добавлен'.format(username)) # Добавляем в свою базу контактов self.repo.add_contact(username) self.repo.commit()
def _get_connection(self): try: conn, addr = self.socket.accept() # Проверка подключений # Должно прийти сообщение о присутствии presence_msg_bytes = conn.recv(1024) presence_msg = JimMessage.create_from_bytes(presence_msg_bytes) if presence_msg.action == PRESENCE: # Получаем имя пользователя client_name = presence_msg.user[ACCOUNT_NAME] print('К нам подключился {}'.format(client_name)) # если клиента нету в базе if not self.repo.client_exists(client_name): # мы его добавляем print('Добавляем клиента') self.repo.add_client(client_name) print('Сохраняем') self.repo.commit() # добавляем историю подключения self.repo.add_history(client_name, addr[0]) self.repo.commit() # отправляем ответ presence_response = JimResponse(**{RESPONSE: OK}) conn.sendall(bytes(presence_response)) else: presence_response = JimResponse(**{RESPONSE: WRONG_REQUEST}) conn.sendall(bytes(presence_response)) except OSError as e: pass # timeout вышел else: print("Получен запрос на соединение от %s" % str(addr)) # Добавляем клиента в список self._clients.append(conn) # Добавляем в словарь имя клиента и соответствующий ему сокет # Мы это делаем, чтобы знать в будующем кому пересылать сообщение self.names[client_name] = conn finally: # Проверить наличие событий ввода-вывода wait = 0 try: r, w, e = select.select(self._clients, self._clients, [], wait) requests = self._read_requests(r) # Получаем входные сообщения self._write_responses( requests) # Выполним отправку входящих сообщений except: pass
def get_contacts(self): """Получить список контактов""" # формируем сообщение list_message = JimMessage(action=GET_CONTACTS, time=time.time(), user=self.name) # отправляем self.socket.send(bytes(list_message)) # дальше слушатель получит ответ, который мы получим из очереди jm = self.request_queue.get() # если там правильный ответ if jm.response == ACCEPTED: # получаем следующее сообщение из очереди, там должен быть список контактов jm = self.request_queue.get() contact_list = jm.action # обновим контакты в базе self.repo.clear_contacts() for contact in contact_list: self.repo.add_contact(contact) self.repo.commit() return contact_list
def _read_requests(self, r_clients): """ Чтение сообщений, которые будут посылать клиенты :param r_clients: клиенты которые могут отправлять сообщения :return: список сообщений """ # Список входящих сообщений messages = [] for sock in r_clients: # Получаем входящие сообщения bdata = sock.recv(2**20) if bdata: jm = JimMessage.create_from_bytes(bdata) # Добавляем в список пару сообщение и сокет который его прислал messages.append((jm, sock)) else: print("Клиент отключился") sock.close() self._clients.remove(sock) # Возвращаем словарь сообщений return messages
def poll(self): self.is_alive = True while True: if not self.is_alive: break data = self.sock.recv(2**20) if data: try: # Если нам пришло сообщение jm = JimMessage.create_from_bytes(data) # Если это message if MESSAGE in jm: # Печатаем в нормальном виде self.process_message(jm) else: # Добавляем сообщение в очередь т.к. это серверное сообщение self.request_queue.put(jm) except MandatoryKeyError: # Если нам пришел ответ от сервера мы его добавляем в очередь для дальнейшей обработки jr = JimResponse.create_from_bytes(data) # При этом поток приостанавливается self.request_queue.put(jr) else: break
def _write_responses(self, messages): """ Теперь будем отправлять сообщения только конкретному пользователю """ for message, sender in messages: # Теперь клиенты отправляют сообщения с разными ключами if message.action == ADD_CONTACT: # нужно добавить контакт клиенту # имя клиента client_username = message.user # имя контакта contact_username = message.user_id # сохраняем данные в базу try: self.repo.add_contact(client_username, contact_username) self.repo.commit() response = JimResponse(**{RESPONSE: OK}) except NoneClientError as e: print('Такой клиент не найден') response = JimResponse(**{RESPONSE: WRONG_REQUEST}) finally: # отправляем пока ответ всем sender.sendall(bytes(response)) elif message.action == DEL_CONTACT: # нужно добавить контакт клиенту # имя клиента client_username = message.user # имя контакта contact_username = message.user_id # сохраняем данные в базу self.repo.del_contact(client_username, contact_username) self.repo.commit() response = JimResponse(**{RESPONSE: OK}) # отправляем пока ответ всем sender.sendall(bytes(response)) elif message.action == GET_CONTACTS: # отдаем список контактов клиенту client_username = message.user # получаем список контактов contact_list = self.repo.get_contacts(client_username) # отправляем ответ что всё ок response = JimResponse(**{ RESPONSE: ACCEPTED, QUANTITY: len(contact_list) }) # отправляем пока ответ всем sender.sendall(bytes(response)) # формируем второе сообщение со списком jm = JimMessage(action=contact_list, time=time.time()) sender.sendall(bytes(jm)) elif message.action == MSG: # получаем кому отправить сообщение to = message.to # на надо только переслать сообщение этому пользователю # получаем сокет по имени # можно даже обойти тут список контактов и отправлять напрямую sock = self.names[to] sock.sendall(bytes(message)) # отвечам тому кто прислал сообщение что все хорошо sender.sendall(bytes(JimResponse(**{RESPONSE: ACCEPTED}))) elif message.action == ADD_AVATAR: avatar_data = JimMessage.base64str_to_bytes( message.avatar_data) self.repo.add_avatar(message.user, avatar_data) self.repo.commit() sender.sendall(bytes(JimResponse(**{RESPONSE: ACCEPTED}))) elif message.action == GET_AVATAR: # отдаем список контактов клиенту client_username = message.user # получаем список контактов try: avatar = self.repo.get_avatar(client_username) except NoneAvatarError: # отправляем ответ что всё не ок response = JimResponse(**{RESPONSE: WRONG_REQUEST}) sender.sendall(bytes(response)) else: response = JimResponse(**{RESPONSE: ACCEPTED}) # отправляем пока ответ всем sender.sendall(bytes(response)) # формируем второе сообщение с аватаром jm = JimMessage( action=JimMessage.bytes_to_base64str(avatar), time=time.time()) sender.sendall(bytes(jm))