class ClientAsync: BUFFER = 1024 port = Port('_port') def __init__(self, loop, addr, port, response_handler): self.loop = loop self.addr = addr self.port = port self.response_handler = response_handler self.response_decoder = lambda x: x.decode() self.request_encoder = lambda x: x.encode() def set_response_decoder(self, value): self.response_decoder = value def set_request_encoder(self, value): self.request_encoder = value def start_background(self): back_lamd = lambda: self.loop.run_until_complete(self.__setup_back()) self.back_thread = threading.Thread(target=back_lamd, daemon=True) self.back_thread.start() async def __setup_back(self): try: asyncio.set_event_loop(self.loop) await self.connect() await asyncio.gather(self.send(), self.read()) except Exception as e: print(e) async def connect(self): self.reader, self.writer = \ await asyncio.open_connection(self.addr, self.port, loop=self.loop) print('\rconnected\n') async def read(self): while True: try: resp = await self.reader.read(self.BUFFER) resp = self.response_decoder(resp) print(f'RESPONCE: {resp}') self.response_handler(resp) except Exception as e: print(f'ER: {e}') return async def send(self): while True: req = await self.input_.get() print(f'REQUEST: {req}') req = self.request_encoder(req) self.writer.write(req) await self.writer.drain()
class ServerAsync: BUFFER = 1024 port = Port('_port') def __init__(self, loop, bind_addr, port, request_handler): self.loop = loop self.addr = bind_addr self.port = port self.request_handler = request_handler self.request_decoder = lambda x: x.decode() self.response_encoder = lambda x: x.encode() def set_request_decoder(self, value): self.request_decoder = value def set_response_encoder(self, value): self.response_encoder = value async def start(self): self.server_cor = \ asyncio.start_server(self.connection_handler, self.addr, self.port, loop=self.loop) self.server = await self.server_cor def start_background(self): back_lamd = lambda: self.loop.run_until_complete(self.__setup_back()) self.back_thread = threading.Thread(target=back_lamd, daemon=True) self.back_thread.start() async def __setup_back(self): asyncio.set_event_loop(self.loop) await self.start() await self.server.wait_closed() async def connection_handler(self, reader, writer): while True: try: data = await reader.read(self.BUFFER) addr = writer.get_extra_info('peername') data = self.request_decoder(data) print(f'{addr} REQUEST: {data}') resp = self.request_handler(data) print(f'RESPONCE: {resp}') resp = self.response_encoder(resp) writer.write(resp) await writer.drain() except Exception as e: print(e) return def stop(self): self.server.close()
class Server(threading.Thread, metaclass=ServerVerifier): port = Port() address = Host() def __init__(self, server_address, server_port, connections, database): self.address = server_address self.port = server_port self.connections = connections self.database = database super().__init__() self.clients = [] self.messages = [] self.names = dict() def init_socket(self): SERV = socket(AF_INET, SOCK_STREAM) try: SERV.bind((self.address, self.port)) except OSError as err: print(err) SERV_LOG.debug('Запуск сервера') SERV.settimeout(0.5) self.sock = SERV self.sock.listen(self.connections) print(f'Сервер запущен {self.address}:{self.port}') def run(self): self.init_socket() while True: try: client, client_addr = self.sock.accept() except OSError: pass else: SERV_LOG.info(f'Подключился клиент: {client_addr}') self.clients.append(client) read_clients_lst = [] send_clients_lst = [] err_lst = [] try: if self.clients: read_clients_lst, send_clients_lst, err_lst = select( self.clients, self.clients, [], 0) except OSError: pass if read_clients_lst: for client_with_message in read_clients_lst: try: self.do_answer(get_message(client_with_message), self.messages, client_with_message, self.clients, self.names) except Exception: SERV_LOG.info( f'Клиент {client_with_message.getpeername()}' f' отключился от сервера') for name in self.names: if self.names[name] == client_with_message: self.database.user_logout(name) del self.names[name] break self.clients.remove(client_with_message) with conflag_lock: new_connection = True for mess in self.messages: try: self.do_message(mess, self.names, send_clients_lst) except Exception: SERV_LOG.info(f'Связь с клиентом {mess[TO]} потеряна') self.clients.remove(self.names[mess[TO]]) self.database.user_logout(mess[TO]) del self.names[mess[TO]] self.messages.clear() # @log def do_answer(self, message, message_list, client, clients, names): """Обрабатывает сообщение от клиента и готовит ответ""" global new_connection SERV_LOG.debug(f'Принято сообщение от клиента: {message}') if ACTION in message and message[ACTION] == PRESENCE \ and TIME in message and USER in message: if message[USER][ACCOUNT_NAME] not in names.keys(): names[message[USER][ACCOUNT_NAME]] = client client_ip, client_port = client.getpeername() self.database.user_login(message[USER][ACCOUNT_NAME], client_ip, client_port) send_message(client, {RESPONSE: 200}) with conflag_lock: new_connection = True SERV_LOG.debug('Ответ подготовлен: {RESPONSE: 200}') else: SERV_LOG.debug("Ответ подготовлен: {RESPONSE: 400\nERROR: \ 'Имя пользователя уже занято'}") send_message(client, { RESPONSE: 400, ERROR: 'Имя пользователя уже занято' }) clients.remove(client) client.close() return elif ACTION in message and message[ACTION] == MSG and TIME in message \ and MESSAGE in message and TO in message: message_list.append(message) self.database.process_user_message(message[SENDER], message[TO]) return elif ACTION in message and message[ACTION] == QUIT and \ ACCOUNT_NAME in message: self.database.user_logout(message[ACCOUNT_NAME]) SERV_LOG.debug('Удален клиент из таблицы активных клиентов') clients.remove(names[message[ACCOUNT_NAME]]) names[message[ACCOUNT_NAME]].close() del names[message[ACCOUNT_NAME]] with conflag_lock: new_connection = True return elif ACTION in message and message[ACTION] == GET_CONTACTS and \ USER in message and self.names[message[USER]] == client: response = {RESPONSE: 202} response[LIST_INFO] = self.database.get_contacts(message[USER]) send_message(client, response) SERV_LOG.info(f'Отправлен ответ на запрос GET_CONTACTS {response}') elif ACTION in message and message[ACTION] == ADD_CONTACT and \ ACCOUNT_NAME in message and USER in message \ and self.names[message[USER]] == client: self.database.add_contact(message[USER], message[ACCOUNT_NAME]) send_message(client, {RESPONSE: 200}) elif ACTION in message and message[ACTION] == REMOVE_CONTACT and \ ACCOUNT_NAME in message and USER in message and \ self.names[message[USER]] == client: self.database.remove_contact(message[USER], message[ACCOUNT_NAME]) send_message(client, {RESPONSE: 200}) elif ACTION in message and message[ACTION] == USERS_REQUEST and \ ACCOUNT_NAME in message and self.names[message[ACCOUNT_NAME]] ==\ client: response[LIST_INFO] = [ user[0] for user in self.database.users_list() ] send_message(client, response) SERV_LOG.info( f'Отправлен ответ на запрос USERS_REQUEST {response}') else: SERV_LOG.debug("Ответ подготовлен: {RESPONSE: 400\nERROR: \ 'Bad request'}") send_message(client, {RESPONSE: 400, ERROR: 'Bad request'}) return @log def do_message(self, message, names, socks): """Отправляет сообщение определённому клиенту""" if message[TO] in names and names[message[TO]] in socks: send_message(names[message[TO]], message) SERV_LOG.info(f'Отправлено сообщение пользователю {message[TO]} ' f' от пользователя {message[SENDER]}') elif message[TO] in names and names[message[TO]] not in socks: raise ConnectionError else: SERV_LOG.error(f'Пользователь {message[TO]} не зарегистрирован на \ на сервере. Отправка невозможна')
class Server(threading.Thread, metaclass=ServerMaker): port = Port() def __init__(self, listen_address, listen_port, database): # Параментры подключения self.addr = listen_address self.port = listen_port # База данных сервера self.database = database # Список подключённых клиентов self.clients = [] # Список сообщений на отправку self.messages = [] # Словарь, содержащий сопоставленные имена и соответствующие им сокеты self.names = dict() # Конструктор предка super().__init__() def init_socket(self): logger.info( f'Запущен сервер, порт для подключений: {self.port} , адрес, с которого принимаются подключения:' f' {self.addr}.' f' Если адрес не указан, принимаются соединения с любых адресов.') # Готовим сокет transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM) transport.bind((self.addr, self.port)) transport.settimeout(0.5) # Начинаем слушать сокет self.sock = transport self.sock.listen() def run(self): # Инициализация сокета self.init_socket() # Основной цикл программы сервера while True: # Ждём подключения, если таймаут вышел, будет исключение try: client, client_address = self.sock.accept() except OSError: pass else: logger.info(f'Установлено соедение с ПК {client_address}') print(f'Установлено соедение с ПК {client_address}') self.clients.append(client) recv_data_lst = [] send_data_lst = [] # Проверяем на наличие ждущих клиентов try: if self.clients: recv_data_lst, send_data_lst, err_lst = select.select( self.clients, self.clients, [], 0) except OSError as error: logger.error(f'Ошибка работы с сокетами: {error}') # Принимаем сообщения и если ошибка, исключаем клиента. if recv_data_lst: for client_with_message in recv_data_lst: try: self.process_client_message( get_message(client_with_message), client_with_message) except (OSError): # Ищем клиента в словаре клиентов и удаляем его из него и базы подключённых logger.info( f'Клиент {client_with_message.getpeername()} отключился от сервера.' ) for name in self.names: if self.names[name] == client_with_message: self.database.user_logout(name) del self.names[name] break self.clients.remove(client_with_message) # Если есть сообщения, обрабатываем каждое for message in self.messages: try: self.process_message(message, send_data_lst) except: logger.info( f'Связь с клиентом с именем {message["to"]} была потеряна' ) self.clients.remove(self.names[message['to']]) self.database.user_logout(message['to']) del self.names[message['to']] self.messages.clear() # Функция адресной отправки сообщения определённому клиенту. Принимает словарь - сообщение, список зарегистрированых # пользователей и слушающие сокеты. Ничего не возвращает. def process_message(self, message, listen_socks): if message['to'] in self.names and self.names[ message['to']] in listen_socks: send_message(self.names[message['to']], message) logger.info( f'Отправлено сообщение пользователю {message["to"]} от пользователя {message["from"]}.' ) print( f'Отправлено сообщение пользователю {message["to"]} от пользователя {message["from"]}.' ) elif message['to'] in self.names and self.names[ message['to']] not in listen_socks: raise ConnectionError else: logger.error( f'Пользователь {message["to"]} не зарегистрирован на сервере, отправка сообщения невозможна.' ) # Обработчик сообщений от клиентов, принимает словарь - сообщение от клиента, проверяет корректность, отправляет # словарь-ответ в случае необходимости. def process_client_message(self, message, client): global new_connection logger.debug(f'Разбор сообщения от клиента : {message}') # Если это сообщение о присутствии, принимаем и отвечаем if 'action' in message and message[ 'action'] == 'presence' and 'time' in message and 'user' in message: # Если такой пользователь ещё не зарегистрирован, регистрируем, иначе отправляем ответ и завершаем # соединение. if message['user']['account_name'] not in self.names.keys(): self.names[message['user']['account_name']] = client client_ip, client_port = client.getpeername() self.database.user_login(message['user']['account_name'], client_ip, client_port) send_message(client, {'response': 200}) with conflag_lock: new_connection = True else: response = { 'response': 400, 'error': 'Имя пользователя уже занято' } send_message(client, response) self.clients.remove(client) client.close() return # Если это сообщение, то добавляем его в очередь сообщений. Ответ не требуется. elif 'action' in message and message['action'] == 'message' and 'to' in message and 'time' in message \ and 'from' in message and 'mess_text' in message and self.names[message['from']] == client: self.messages.append(message) self.database.process_message(message['from'], message['to']) return # Если клиент выходит elif 'action' in message and message[ 'action'] == 'exit' and 'account_name' in message: self.database.user_logout(message['account_name']) self.clients.remove(self.names['account_name']) self.names['account_name'].close() del self.names['account_name'] with conflag_lock: new_connection = True return # Если это запрос контакт-листа elif 'action' in message and message['action'] == 'get_contacts' and 'user' in message and \ self.names[message['user']] == client: response = {'response': 202, 'data_list': None} response['data_list'] = self.database.get_contacts(message['user']) send_message(client, response) # Если это добавление контакта elif 'action' in message and message['action'] == 'add' and 'account_name' in message and 'user' in message \ and self.names[message['user']] == client: self.database.add_contact(message['user'], message['account_name']) send_message(client, {'response': 200}) # Если это удаление контакта elif 'action' in message and message['action'] == 'remove' and 'account_name' in message and 'user' in message \ and self.names[message['user']] == client: self.database.remove_contact(message['user'], message['account_name']) send_message(client, {'response': 200}) # Если это запрос известных пользователей elif 'action' in message and message['action'] == 'get_users' and 'account_name' in message \ and self.names[message['account_name']] == client: response = {'response': 202} response['data_list'] = [ user[0] for user in self.database.users_list() ] send_message(client, response) # Иначе отдаём Bad request else: response = {'response': 400, 'error': 'Запрос некорректен'} send_message(client, response) return
class Client: """ Class client connection and data exchange """ __slots__ = ('addr', '_port', 'user', 'logger', 'socket', 'connected', 'get_chat_sended', 'listener', 'sender', 'encryptors', 'priv_key', 'storage', 'subs', 'answers', 'file_answers', 'executor', 'execute_queue') TCP = (AF_INET, SOCK_STREAM) port = Port('_port') def __init__(self, addr, port): self.logger = logging.getLogger(log_config.LOGGER_NAME) self.addr = addr self.port = port self.connected = self.get_chat_sended = False self.subs = {} # self.subs = {201: [], 202: [], 203: [], 204: [], 205: []} self.answers = queue.Queue() self.file_answers = queue.Queue() self.execute_queue = queue.Queue() self.encryptors = {} @property def username(self): return self.user.username def get_encryptor(self, contact): return self.encryptors[contact] if contact in self.encryptors else None def set_encryptor(self, contact, value): self.encryptors[contact] = value def set_user(self, username, password): self.user = User(username, password) self.storage = ClientStorage(username) def start(self): """ Method start connection to server """ self.socket = socket(*self.TCP) start_txt = f'Connect to {self.addr}:{self.port} as {self.username}' self.logger.debug(start_txt) print(start_txt) self.__connect() @try_except_wrapper def __connect(self): self.socket.connect((self.addr, self.port)) self.connected = True print('Done') response = self.authorization() if response.code != OK: show_error(str(response.message)) self.logger.warning(response) exit() self.listener = ClientThread(self.__listen_server, self.logger) self.listener.start() self.executor = ClientThread(self.__execute, self.logger) self.executor.start() def __execute(self): self.logger.debug('EXECUTER STARTED') while self.connected: func, *args = self.execute_queue.get() self.logger.debug(f'{func} | {args}') try: func(*args) except Exceptiona as e: self.logger.error(e) @try_except_wrapper def __send_request(self, request): if not self.connected: return self.logger.debug(request) send_data(self.socket, request) @try_except_wrapper def __get_response(self): if not self.connected: return None response = get_data(self.socket) self.logger.debug(response) return response @try_except_wrapper def authorization(self): """ Method of authorization on server """ pr_req = Request(RequestAction.PRESENCE, self.user.username) self.__send_request(pr_req) resp = self.__get_response() if resp is None: return Response(SERVER_ERROR) if resp.code != AUTH: return resp enc_pass = encrypt_rsa(import_pub_key(resp.message.encode()), self.user.password) auth_req = Request(RequestAction.AUTH, enc_pass.decode()) self.__send_request(auth_req) return self.__get_response() def get_chat_req(self, contact): """ Method send request for gets all messages of chat with contact """ if self.get_chat_sended: return req = Request(RequestAction.COMMAND, f'get_chat {self.user.username} {contact}') self.__send_request(req) def get_users_req(self): """ Method send request for gets users online """ self.__send_request(Request(RequestAction.COMMAND, 'get_users')) def get_contacts_req(self): """ Method send request for gets list contacts """ self.__send_request(Request(RequestAction.COMMAND, 'get_contacts')) @try_except_wrapper def start_chat(self, contact): """ Method initialization of chat with contact """ key = self.storage.get_key(contact) if key is not None: self.set_encryptor(contact, ClientCrypt(key)) prv, pub = gen_keys() self.priv_key = prv msg = Msg(pub.export_key().decode(), self.username, contact) start_req = Request(RequestAction.START_CHAT, msg) self.__send_request(start_req) @try_except_wrapper def accepting_chat(self, resp_mes): """ Method of handle request to start chat """ r_msg = Msg.from_formated(resp_mes) pub = import_pub_key(r_msg.text.encode()) key = self.storage.get_key(r_msg.sender) if key is not None: encryptor = ClientCrypt(key) else: encryptor = ClientCrypt.gen_secret(self.username, r_msg.sender) self.storage.add_chat_key(r_msg.sender, encryptor.secret) self.set_encryptor(r_msg.sender, encryptor) enc_key = encrypt_rsa(pub, encryptor.secret) msg = Msg(enc_key.decode(), self.username, r_msg.sender) accept_req = Request(RequestAction.ACCEPT_CHAT, msg) self.__send_request(accept_req) @try_except_wrapper def accepted_chat(self, resp_mes): """ Method of handle response about confirm start of chat """ msg = Msg.from_formated(resp_mes) encryptor = self.get_encryptor(msg.sender) if encryptor is not None: return secret = decrypt_rsa(self.priv_key, msg.text.encode()) self.set_encryptor(msg.sender, ClientCrypt(secret)) self.storage.add_chat_key(msg.sender, secret) def add_contact(self, contact): """ Method add contact in contact list """ if self.storage.get_contact(contact): return False self.storage.add_contact(contact) req = Request(RequestAction.COMMAND, f'add_contact {contact}') self.__send_request(req) return True def rem_contact(self, contact): """ Method remove contact from contact list """ self.storage.remove_contact(contact) req = Request(RequestAction.COMMAND, f'rem_contact {contact}') self.__send_request(req) def sync_contacts(self, contacts): """ Method sync of list contact from server to client """ for contact in contacts: self.storage.append_contact(contact) @try_except_wrapper def save_avatar(self, avatar_bytes): self.storage.set_avatar(avatar_bytes) self.send_avatar(avatar_bytes) @property def avatar(self): value = self.storage.get_avatar(self.username) if value: return value.avatar @avatar.setter def avatar(self, value): self.storage.set_avatar(self.username, value) self.send_avatar_async(value) def send_avatar_async(self, avatar_bytes): sender_thread = ClientThread(lambda: self.send_avatar(avatar_bytes), self.logger) sender_thread.start() @try_except_wrapper def send_avatar(self, avatar_bytes): avatar_part = 512 for i in range(0, len(avatar_bytes), avatar_part): part = b64encode(avatar_bytes[i:i + avatar_part]) part_req = Request(RequestAction.IMAGE, part.decode()) self.__send_request(part_req) self.file_answers.get() self.logger.debug(f'Send end part') end_req = Request(RequestAction.END_IMAGE, 'set_avatar') self.__send_request(end_req) resp = self.file_answers.get() @try_except_wrapper def check_self_avatar(self): user = self.username av_hash = self.storage.get_avatar_hash(self.username) ch_req = Request(RequestAction.COMMAND, f'check_avatar {user} {av_hash}') self.__send_request(ch_req) resp = self.answers.get() if not resp: self.send_avatar(self.avatar) @try_except_wrapper def get_user_avatar(self, user): avatar = self.storage.get_avatar(user) if avatar: ch_req = Request(RequestAction.COMMAND, f'check_avatar {user} {avatar.avatar_hash}') self.__send_request(ch_req) resp = self.answers.get() if resp == 1: return avatar.avatar get_req = Request(RequestAction.GET_IMAGE, user) self.__send_request(get_req) avatar_bytes = b'' while True: resp = self.file_answers.get() if not resp: break avatar_bytes += b64decode(resp.encode()) self.storage.set_avatar(user, avatar_bytes) return avatar_bytes pass @try_except_wrapper def send_msg(self, text, to): """ Method send messge to server """ if to != '@ALL': encryptor = self.get_encryptor(to) text = encryptor.encript_msg(text.encode()).decode() else: text = b64encode(text.encode()).decode() msg = Msg(text, self.user, to) if to != '@ALL': self.storage.add_message(msg.to, msg.text) request = Request(RequestAction.MESSAGE, msg) self.__send_request(request) def __listen_server(self): """ Method listen responses from server """ while self.connected: resp = get_data(self.socket) self.logger.debug(resp) if resp.type != RESPONSE: self.logger.warning(f'Received not RESPONSE:\n {resp}') continue if resp.code == ANSWER: self.answers.put(resp.message) elif resp.code == FILE_ANSWER: self.file_answers.put(resp.message) elif resp.code in self.subs.keys(): for sub in self.subs[resp.code]: # sub(resp.message) self.execute_queue.put((sub, resp.message)) # else: # self.logger.debug(resp.message) @try_except_wrapper def get_collection_response(self): result = [] while True: resp = self.answers.get(timeout=60) if not resp: break result.append(resp) return result def subscribe(self, code, func): """ Method subscribe of function to response code """ if code in self.subs.keys(): self.subs[code].append(func) else: self.subs[code] = [func] def parse_recv_message(self, msg): """ Method parse/decrypt message """ msg = Msg.from_formated(msg) if msg.to != '@ALL': encryptor = self.get_encryptor(msg.sender) msg.text = encryptor.decrypt_msg(msg.text.encode()).decode() else: msg.text = b64decode(msg.text).decode() return msg.sender, msg.text, msg.to
class Server(metaclass=ServerMaker): port = Port() def __init__(self, args): self.addr = args.a self.port = args.p def process_request(self, request): LOG.debug('process_client_msg: %s', request) response = get_jim_response_error(400, 'Bad request') msg = None if not (ACTION in request and TIME in request): pass elif request[ACTION] == ACTION_PRESENCE: if (USER in request and request[USER][ACCOUNT_NAME] == 'Guest'): response = get_jim_response(200) elif request[ACTION] == ACTION_MSG: if (TO in request and FROM in request and ENCODING in request and MESSAGE in request): response = get_jim_response(200) msg = request return response, msg def read_requests(self, r_clients, all_clients): requests = {} for client_socket in r_clients: try: data = get_message(client_socket) requests[client_socket] = data except Exception as e: print( f'Клиент {client_socket.fileno()} {client_socket.getpeername()} отключился' ) all_clients.remove(client_socket) return requests def write_requests(self, requests, w_clients, all_clients, messages_list): for client_socket in requests: request_data = requests[client_socket] response, msg = self.process_request(request_data) if msg: messages_list.append(msg) if client_socket in w_clients: try: send_message(client_socket, response) except Exception as e: print( f'Клиент {client_socket.fileno()} {client_socket.getpeername()} отключился' ) client_socket.close() all_clients.remove(client_socket) def write_messages(self, msg_list, w_clients, all_clients): msg_list_copy = deepcopy(msg_list) for msg in msg_list_copy: for client_socket in w_clients: try: send_message(client_socket, msg) except Exception as e: print( f'Клиент {client_socket.fileno()} {client_socket.getpeername()} отключился' ) client_socket.close() all_clients.remove(client_socket) msg_list.remove(msg) def main_loop(self, ): LOG.debug('create socket') with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as transport: transport.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) LOG.debug('bind socket to %(a)s:%(p)s', self.addr, self.port) transport.bind((self.addr, self.port)) LOG.debug('start listening') transport.listen(MAX_CONNECTIONS) transport.settimeout(0.2) clients = [] msg_list = [] while True: try: client, client_addr = transport.accept() except OSError as e: pass # timeout else: LOG.info(f'Получен запрос на соединение от {client_addr}') clients.append(client) finally: if not clients: continue r = [] w = [] try: r, w, _ = select.select(clients, clients, [], 0) except Exception as e: print(f'Кто-то отключился\n{e}') if not r: continue requests = self.read_requests(r, clients) self.write_requests(requests, w, clients, msg_list) self.write_messages(msg_list, w, clients)
class Server(metaclass=ServerVerifier): port = Port() address = Host() def __init__(self, server_address, server_port, connections, database): self.address = server_address self.port = server_port self.connections = connections self.database = database def __call__(self): SERV_LOG.debug('Запуск сервера') SERV = socket(AF_INET, SOCK_STREAM) while True: try: SERV.bind((self.address, self.port)) print(f'Сервер запущен {self.address}:{self.port}') break except OSError as err: print(f'Порт занят. Повторная попытка запуска сервера через 10\ сек') SERV_LOG.debug(f'Ошибка при запуске сервера: {err}') sleep(10) SERV.listen(self.connections) SERV.settimeout(0.5) clients = [] messages = [] names = dict() while True: try: client, client_addr = SERV.accept() except OSError: pass else: SERV_LOG.info(f'Подключился клиент: {client_addr}') clients.append(client) read_clients_lst = [] send_clients_lst = [] err_lst = [] try: if clients: read_clients_lst, send_clients_lst, err_lst = select( clients, clients, [], 0) except OSError: pass if read_clients_lst: for client_with_message in read_clients_lst: try: self.do_answer(get_message(client_with_message), messages, client_with_message, clients, names) except Exception: SERV_LOG.info( f'Клиент {client_with_message.getpeername()}' f' отключился от сервера') for name in self.names: if names[name] == client_with_message: self.database.user_logout(name) del names[name] break clients.remove(client_with_message) for i in messages: try: self.do_message(i, names, send_clients_lst) except Exception: SERV_LOG.info(f'Связь с клиентом {i[TO]} потеряна') clients.remove(names[i[TO]]) self.database.user_logout(i[TO]) del names[i[TO]] messages.clear() @log def do_answer(self, message, message_list, client, clients, names): """Обрабатывает сообщение от клиента и готовит ответ""" SERV_LOG.debug('Обработка сообщения от клиента и подготовка ответа') if ACTION in message and message[ACTION] == PRESENCE and TO in message\ and TIME in message and USER in message: if message[USER][ACCOUNT_NAME] not in names.keys(): names[message[USER][ACCOUNT_NAME]] = client client_ip, client_port = client.getpeername() self.database.user_login(message[USER][ACCOUNT_NAME], client_ip, client_port) send_message(client, {RESPONSE: 200}) SERV_LOG.debug('Ответ подготовлен: {RESPONSE: 200}') else: SERV_LOG.debug("Ответ подготовлен: {RESPONSE: 400\nERROR: \ 'Имя пользователя уже занято'}") send_message(client, { RESPONSE: 400, ERROR: 'Имя пользователя уже занято' }) clients.remove(client) client.close() return elif ACTION in message and message[ACTION] == MSG and TIME in message \ and MESSAGE in message and TO in message: message_list.append(message) return elif ACTION in message and message[ACTION] == QUIT and \ ACCOUNT_NAME in message: self.database.user_logout(message[ACCOUNT_NAME]) clients.remove(names[message[ACCOUNT_NAME]]) names[message[ACCOUNT_NAME]].close() del names[message[ACCOUNT_NAME]] else: SERV_LOG.debug("Ответ подготовлен: {RESPONSE: 400\nERROR: \ 'Bad request'}") send_message(client, {RESPONSE: 400, ERROR: 'Bad request'}) return @log def do_message(self, message, names, socks): """Отправляет сообщение определённому клиенту""" if message[TO] in names and names[message[TO]] in socks: send_message(names[message[TO]], message) SERV_LOG.info(f'Отправлено сообщение пользователю {message[TO]} ' f' от пользователя {message[SENDER]}') elif message[TO] in names and names[message[TO]] not in socks: raise ConnectionError else: SERV_LOG.error(f'Пользователь {message[TO]} не зарегистрирован на \ на сервере. Отправка невозможна')
class Client: __slots__ = ('_addr', '_port', 'logger', 'socket', 'connected', 'listener', 'sender') TCP = (AF_INET, SOCK_STREAM) USER = User(f'Test{random.randint(0, 1000)}') addr = Addr('_addr') port = Port('_port') def __init__(self, addr, port): self.logger = logging.getLogger(log_config.LOGGER_NAME) self.addr = addr self.port = port self.connected = False def start(self): self.socket = socket(*self.TCP) start_txt = f'Connect to {self.addr}:{self.port} as {self.USER}...' self.logger.debug(start_txt) print(start_txt) self.__connect() @try_except_wrapper def __connect(self): self.socket.connect((self.addr, self.port)) self.connected = True print('Done') print_help() response = self.presence() if response.code != OK: self.logger.warning(response) return self.listener = ClientThread(self.__listen_server, self.logger) self.listener.start() self.send_msg() @try_except_wrapper def __send_request(self, request): if not self.connected: return self.logger.debug(request) send_data(self.socket, request) @try_except_wrapper def __get_response(self): if not self.connected: return response = get_data(self.socket) self.logger.debug(response) return response def presence(self): request = Request(RequestAction.PRESENCE, self.USER) self.__send_request(request) return self.__get_response() def send_msg(self): while self.connected: msg = input('Enter message:\n') if msg.upper() == 'Q': break if msg[0] == '!': self.__execute_local_command(msg[1:]) continue if msg[0] == '#': request = Request(RequestAction.COMMAND, msg[1:]) else: msg = Msg(msg, self.USER) msg.parse_msg() request = Request(RequestAction.MESSAGE, msg) self.__send_request(request) def __execute_local_command(self, command): if command == 'help': print_help() elif command == 'set_name': name = input('Set new name') self.USER.username = name self.__send_request(Request(RequestAction.PRESENCE, self.USER)) elif command == 'reconnect': self.start() else: print('Command not found') def __listen_server(self): while self.connected: resp = get_data(self.socket) self.logger.debug(resp) if resp.type != RESPONSE: self.logger.warning(f'Received not RESPONSE:\n {resp}') continue if resp.code == 101: print(f'server: {resp.message}') else: print(resp.message)
class Client: """ Class client connection and data exchange """ __slots__ = ('_addr', '_port', 'user', 'logger', 'socket', 'connected', 'listener', 'sender', 'encryptors', 'priv_key', 'storage', 'subs', 'answers') TCP = (AF_INET, SOCK_STREAM) addr = Addr('_addr') port = Port('_port') def __init__(self, addr, port): self.logger = logging.getLogger(log_config.LOGGER_NAME) self.addr = addr self.port = port self.connected = False self.subs = {} # self.subs = {201: [], 202: [], 203: [], 204: [], 205: []} self.answers = queue.Queue() self.encryptors = {} @property def username(self): return self.user.username def get_encryptor(self, contact): return self.encryptors[contact] if contact in self.encryptors else None def set_encryptor(self, contact, value): self.encryptors[contact] = value def set_user(self, username, password): self.user = User(username, password) self.storage = ClientStorage(username) def start(self): """ Method start connection to server """ self.socket = socket(*self.TCP) start_txt = f'Connect to {self.addr}:{self.port} as {self.username}' self.logger.debug(start_txt) print(start_txt) self.__connect() @try_except_wrapper def __connect(self): self.socket.connect((self.addr, self.port)) self.connected = True print('Done') response = self.authorization() if response.code != OK: show_error(str(response.message)) self.logger.warning(response) return self.listener = ClientThread(self.__listen_server, self.logger) self.listener.start() @try_except_wrapper def __send_request(self, request): if not self.connected: return self.logger.debug(request) send_data(self.socket, request) @try_except_wrapper def __get_response(self): if not self.connected: return None response = get_data(self.socket) self.logger.debug(response) return response @try_except_wrapper def authorization(self): """ Method of authorization on server """ pr_req = Request(RequestAction.PRESENCE, self.user.username) self.__send_request(pr_req) resp = self.__get_response() if resp is None: return Response(SERVER_ERROR) if resp.code != AUTH: return resp enc_pass = encrypt_rsa(import_pub_key(resp.message.encode()), self.user.password) auth_req = Request(RequestAction.AUTH, enc_pass.decode()) self.__send_request(auth_req) return self.__get_response() def get_chat_req(self, contact): """ Method send request for gets all messages of chat with contact """ req = Request(RequestAction.COMMAND, f'get_chat {self.user.username} {contact}') self.__send_request(req) def get_users_req(self): """ Method send request for gets users online """ self.__send_request(Request(RequestAction.COMMAND, 'get_users')) def get_contacts_req(self): """ Method send request for gets list contacts """ self.__send_request(Request(RequestAction.COMMAND, 'get_contacts')) @try_except_wrapper def start_chat(self, contact): """ Method initialization of chat with contact """ key = self.storage.get_key(contact) if key is not None: self.set_encryptor(contact, ClientCrypt(key)) prv, pub = gen_keys() self.priv_key = prv msg = Msg(pub.export_key().decode(), self.username, contact) start_req = Request(RequestAction.START_CHAT, msg) self.__send_request(start_req) @try_except_wrapper def accepting_chat(self, resp_mes): """ Method of handle request to start chat """ r_msg = Msg.from_formated(resp_mes) pub = import_pub_key(r_msg.text.encode()) key = self.storage.get_key(r_msg.sender) if key is not None: encryptor = ClientCrypt(key) else: encryptor = ClientCrypt.gen_secret(self.username, r_msg.sender) self.storage.add_chat_key(r_msg.sender, encryptor.secret) self.set_encryptor(r_msg.sender, encryptor) enc_key = encrypt_rsa(pub, encryptor.secret) msg = Msg(enc_key.decode(), self.username, r_msg.sender) accept_req = Request(RequestAction.ACCEPT_CHAT, msg) self.__send_request(accept_req) @try_except_wrapper def accepted_chat(self, resp_mes): """ Method of handle response about confirm start of chat """ msg = Msg.from_formated(resp_mes) encryptor = self.get_encryptor(msg.sender) if encryptor is not None: return secret = decrypt_rsa(self.priv_key, msg.text.encode()) self.set_encryptor(msg.sender, ClientCrypt(secret)) self.storage.add_chat_key(msg.sender, secret) def add_contact(self, contact): """ Method add contact in contact list """ if self.storage.get_contact(contact): return False self.storage.add_contact(contact) req = Request(RequestAction.COMMAND, f'add_contact {contact}') self.__send_request(req) return True def rem_contact(self, contact): """ Method remove contact from contact list """ self.storage.remove_contact(contact) req = Request(RequestAction.COMMAND, f'rem_contact {contact}') self.__send_request(req) def sync_contacts(self, contacts): """ Method sync of list contact from server to client """ for contact in contacts: self.storage.append_contact(contact) @try_except_wrapper def send_msg(self, text, to): """ Method send messge to server """ encryptor = self.get_encryptor(to) text = encryptor.encript_msg(text.encode()).decode() msg = Msg(text, self.user, to) self.storage.add_message(msg.to, msg.text) request = Request(RequestAction.MESSAGE, msg) self.__send_request(request) def __listen_server(self): """ Method listen responses from server """ while self.connected: resp = get_data(self.socket) self.logger.debug(resp) if resp.type != RESPONSE: self.logger.warning(f'Received not RESPONSE:\n {resp}') continue if resp.code == ANSWER: self.answers.put(resp.message) print(f'server: {resp.message}') elif resp.code in self.subs.keys(): for sub in self.subs[resp.code]: sub(resp.message) else: print(resp.message) def subscribe(self, code, func): """ Method subscribe of function to response code """ if code in self.subs.keys(): self.subs[code].append(func) else: self.subs[code] = [func] def parse_recv_message(self, msg): """ Method parse/decrypt message """ msg = Msg.from_formated(msg) encryptor = self.get_encryptor(msg.sender) msg.text = encryptor.decrypt_msg(msg.text.encode()).decode() return msg.sender, msg.text
class Server: """ Class implement receive, handle, response to client request """ __slots__ = ('bind_addr', '_port', 'logger', 'socket', 'clients', 'users', 'client_keys', 'listener', 'storage', 'commands', 'request_handlers') TCP = (AF_INET, SOCK_STREAM) TIMEOUT = 5 port = Port('_port') def __init__(self, bind_addr, port): self.logger = logging.getLogger(log_config.LOGGER_NAME) self.bind_addr = bind_addr self.port = port self.clients = [] self.client_keys = {} self.users = {} self.storage = ServerStorage() self.__init_commands() self.__init_req_handlers() def __init_commands(self): """ Method fills dictionary commands """ self.commands = { 'get_users': self.storage.get_users_online, 'add_contact': self.storage.add_contact, 'rem_contact': self.storage.remove_contact, 'get_contacts': self.storage.get_contacts, 'get_chat': self.storage.get_chat_str } def __init_req_handlers(self): """ Method fills dictionary request handlers """ self.request_handlers = { RequestAction.PRESENCE: self.__req_presence_handler, RequestAction.AUTH: self.__req_auth_handler, RequestAction.QUIT: lambda r, c, *a: self.__client_disconnect(c), RequestAction.START_CHAT: self.__req_start_chat_handler, RequestAction.ACCEPT_CHAT: self.__req_accept_chat_handler, RequestAction.MESSAGE: self.__req_message_handler, RequestAction.COMMAND: self.__req_command_handler, } def start(self, request_count=5): """ Method the start configuration server """ self.socket = socket(*self.TCP) self.socket.settimeout(0.5) self.socket.bind((self.bind_addr, self.port)) start_msg = f'Config server port - {self.port}| ' \ f'Bind address - {self.bind_addr}' self.logger.info(start_msg) self.socket.listen(request_count) self.listener = ServerThread(self.__listen, self.logger) self.listener.start() def __listen(self): """ Method the listener client connections """ self.logger.info('Start listen') while True: try: client, addr = self.socket.accept() except OSError: pass except Exception as ex: self.logger.error(ex) else: self.logger.info(f'Connection from {addr}') self.clients.append(client) i_clients, o_clients = [], [] try: i_clients, o_clients, ex = select(self.clients, self.clients, [], self.TIMEOUT) except OSError: pass except Exception as exc: self.logger.error(exc) requests = self.__get_requests(i_clients) if requests: self.__send_responses(requests, o_clients) @try_except_wrapper def __get_requests(self, i_clients): """ Method the handler of client requests """ requests = {} for client in i_clients: try: request = get_data(client) requests[client] = request if request.action == RequestAction.PRESENCE: if request.body in self.users: requests.pop(client) send_data(client, Response(CONFLICT)) self.clients.remove(client) else: self.users[request.body] = client elif request.action == RequestAction.QUIT: self.__client_disconnect(client) except (ConnectionError, ValueError): self.__client_disconnect(client) except Exception as e: raise e return requests @try_except_wrapper def __send_responses(self, requests, o_clients): """ Method the sender of responses to clients """ for client, i_req in requests.items(): other_clients = [c for c in o_clients if c != client] self.logger.info(client) self.logger.info(i_req) action = i_req.action if action in self.request_handlers: self.request_handlers[action](i_req, client, other_clients) else: self.__send_to_client(client, Response(INCORRECT_REQUEST)) self.logger.error(f'Incorrect request:\n {i_req}') @try_except_wrapper def __send_to_client(self, client, resp): try: self.logger.debug(resp) send_data(client, resp) except ConnectionError: self.__client_disconnect(client) except Exception as e: raise e def __send_to_all(self, clients, resp): for cl in clients: self.__send_to_client(cl, resp) @try_except_wrapper def __client_disconnect(self, client): self.clients.remove(client) user = [u for u, c in self.users.items() if c == client].pop() self.users.pop(user) self.storage.logout_user(user) disconnection_response = Response(DISCONNECTED, user) self.logger.debug(disconnection_response) for cl in self.clients: send_data(cl, disconnection_response) def __execute_command(self, command, *args): if command in self.commands: answer = self.commands[command](*args) if answer is False: return Response(SERVER_ERROR, 'Command error') elif isinstance(answer, list): answer = [str(a) for a in answer] return Response(ANSWER, answer) elif answer is None: return Response(ANSWER, 'Done') return Response(ANSWER, answer) else: return Response(INCORRECT_REQUEST, 'Command not found') # region Request handlers @try_except_wrapper def __req_presence_handler(self, i_req, client, *args): """ Mathod the handler presence request """ prv, pub = gen_keys() self.client_keys[i_req.body] = (client, prv) self.__send_to_client(client, Response(AUTH, pub.export_key().decode())) @try_except_wrapper def __req_auth_handler(self, i_req, client, *args): """ Mathod the handler authorization request """ other_clients = args[0] user = [u for u, c in self.users.items() if c == client] if len(user) == 0: self.logger.warning(f'AUTH: user not found') return user = user[0] cl, key = self.client_keys[user] if cl != client: self.logger.warning('AUTH: connection sockets not equals') return password = decrypt_password(key, i_req.body) if password is None: self.logger.warning('AUTH: decrypt error') return password_hash = get_hash_password(password, user.encode()) if not self.storage.authorization_user(user, password_hash): self.__send_to_client(client, Response(UNAUTHORIZED)) self.clients.remove(client) self.users.pop(user) return self.storage.login_user(user, client.getpeername()[0]) self.__send_to_client(client, Response(OK)) self.__send_to_all(other_clients, Response(CONNECTED, user)) @try_except_wrapper def __req_start_chat_handler(self, i_req, client, *args): """ Mathod the handler start chat request """ msg = Msg.from_dict(i_req.body) if msg.to not in self.users: self.logger.warning(f'{msg.to} not found') return self.__send_to_client(self.users[msg.to], Response(START_CHAT, str(msg))) @try_except_wrapper def __req_accept_chat_handler(self, i_req, client, *args): """ Mathod the handler accept chat request """ msg = Msg.from_dict(i_req.body) if msg.to not in self.users: self.logger.warning(f'{msg.to} not found') return self.__send_to_client(self.users[msg.to], Response(ACCEPT_CHAT, str(msg))) @try_except_wrapper def __req_message_handler(self, i_req, client, *args): """ Mathod the handler message request """ other_clients = args[0] msg = Msg.from_dict(i_req.body) self.storage.user_stat_update(msg.sender, ch_sent=1) if msg.to.upper() != 'ALL' and msg.to in self.users: self.storage.user_stat_update(msg.to, ch_recv=1) self.storage.add_message(msg.sender, msg.to, msg.text) self.__send_to_client(self.users[msg.to], Response(LETTER, str(msg))) else: self.__send_to_all(other_clients, Response(LETTER, str(msg))) for u in self.storage.get_users_online(): if str(u) == msg.sender: continue self.storage.user_stat_update(str(u), ch_recv=1) self.storage.add_message(msg.sender, str(u), msg.text) @try_except_wrapper def __req_command_handler(self, i_req, client, *args): """ Mathod the handler command request """ command, *args = i_req.body.split() user = [u for u, c in self.users.items() if c == client].pop() if len(args) < 1 or args[0] != user: args.insert(0, user) o_resp = self.__execute_command(command, *args) self.__send_to_client(client, o_resp)
class Server: __slots__ = ('bind_addr', '_port', 'logger', 'socket', 'clients', 'users', 'storage', 'commands', 'listener') TCP = (AF_INET, SOCK_STREAM) TIMEOUT = 5 port = Port('_port') def __init__(self, bind_addr, port): self.logger = logging.getLogger(log_config.LOGGER_NAME) self.bind_addr = bind_addr self.port = port self.clients = [] self.users = {} self.storage = ServerStorage() self.__init_commands() def __init_commands(self): self.commands = { 'get_users': self.storage.get_users_online, 'add_contact': self.storage.add_contact, 'rem_contact': self.storage.remove_contact, 'get_contacts': self.storage.get_contacts, } def start(self, request_count=5): self.socket = socket(*self.TCP) self.socket.settimeout(0.5) self.socket.bind((self.bind_addr, self.port)) self.logger.info( f'Config server port - {self.port}| Bind address - {self.bind_addr}' ) self.socket.listen(request_count) self.listener = ServerThread(self.__listen, self.logger) self.listener.start() self.__console() def __console(self): while True: msg = input('Enter command:\n') if msg.upper() == 'Q': break if msg[0] == '#': msg = msg[1:] command, *args = msg.split(' ') if command in self.commands: res = self.commands[command](*args) print(res) def __listen(self): self.logger.info('Start listen') while True: try: client, addr = self.socket.accept() except OSError: pass except Exception as ex: self.logger.error(ex) else: self.logger.info(f'Connection from {addr}') self.clients.append(client) i_clients, o_clients = [], [] try: i_clients, o_clients, ex = select(self.clients, self.clients, [], self.TIMEOUT) except OSError: pass except Exception as ex: self.logger.error(ex) requests = self.__get_requests(i_clients) if requests: self.__send_responses(requests, o_clients) @try_except_wrapper def __get_requests(self, i_clients): requests = {} for client in i_clients: try: request = get_data(client) requests[client] = request if request.action == RequestAction.PRESENCE: if request.body in self.users: requests.pop(client) send_data(client, Response(CONFLICT)) self.clients.remove(client) else: self.users[request.body] = client self.storage.login_user(request.body, client.getpeername()[0]) elif request.action == RequestAction.QUIT: self.__client_disconnect(client) except (ConnectionError, ValueError): self.__client_disconnect(client) except Exception as e: raise e return requests @try_except_wrapper def __send_responses(self, requests, o_clients): for client, i_req in requests.items(): other_clients = [c for c in o_clients if c != client] self.logger.info(client) self.logger.info(i_req) if i_req.action == RequestAction.PRESENCE: self.__send_to_client(client, Response(OK)) self.__send_to_all(other_clients, Response(BASIC, f'{i_req.body} connected')) elif i_req.action == RequestAction.QUIT: self.__client_disconnect(client) elif i_req.action == RequestAction.MESSAGE: msg = Msg.from_dict(i_req.body) if msg.to.upper() != 'ALL' and msg.to in self.users: self.__send_to_client(self.users[msg.to], Response(BASIC, str(msg))) else: self.__send_to_all(other_clients, Response(BASIC, str(msg))) elif i_req.action == RequestAction.COMMAND: command, *args = i_req.body.split() user = [u for u, c in self.users.items() if c == client].pop() args.insert(0, user) # o_resp = Response(ANSWER, self.__execute_command(command, *args)) o_resp = self.__execute_command(command, *args) self.__send_to_client(client, o_resp) else: self.__send_to_client(client, Response(INCORRECT_REQUEST)) self.logger.error(f'Incorrect request:\n {i_req}') @try_except_wrapper def __send_to_client(self, client, resp): try: send_data(client, resp) except ConnectionError: self.__client_disconnect(client) except Exception as e: raise e def __send_to_all(self, clients, resp): for cl in clients: self.__send_to_client(cl, resp) @try_except_wrapper def __client_disconnect(self, client): self.clients.remove(client) disconnected_user = [u for u, c in self.users.items() if c == client].pop() self.users.pop(disconnected_user) self.storage.logout_user(disconnected_user) disconnection_response = Response(BASIC, f'{disconnected_user} disconnected') for cl in self.clients: send_data(cl, disconnection_response) def __execute_command(self, command, *args): if command in self.commands: answer = self.commands[command](*args) if answer is False: return Response(SERVER_ERROR, 'Command error') elif isinstance(answer, list): answer = [str(a) for a in answer] return Response(ANSWER, answer) elif answer is None: return Response(ANSWER, 'Done') return Response(ANSWER, answer) else: return Response(INCORRECT_REQUEST, 'Command not found')
class Server(metaclass=ServerMaker): port = Port() def __init__(self, listen_address, listen_port): # Параментры подключения self.addr = listen_address self.port = listen_port # Список подключённых клиентов. self.clients = [] # Список сообщений на отправку. self.messages = [] # Словарь, содержащий сопоставленные имена и соответствующие им сокеты. self.names = dict() def init_socket(self): logger.info( f'Запущен сервер, порт для подключений: {self.port} , адрес с которого принимаются подключения:' f' {self.addr}.' f' Если адрес не указан, принимаются соединения с любых адресов.') # Готовим сокет transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM) transport.bind((self.addr, self.port)) transport.settimeout(0.5) # Начинаем слушать сокет. self.sock = transport self.sock.listen() def main_loop(self): # Инициализация Сокета self.init_socket() # Основной цикл программы сервера while True: # Ждём подключения, если таймаут вышел, ловим исключение. try: client, client_address = self.sock.accept() except OSError: pass else: logger.info(f'Установлено соедение с ПК {client_address}') self.clients.append(client) recv_data_lst = [] send_data_lst = [] # Проверяем на наличие ждущих клиентов try: if self.clients: recv_data_lst, send_data_lst, err_lst = select.select( self.clients, self.clients, [], 0) except OSError: pass # принимаем сообщения и если ошибка, исключаем клиента. if recv_data_lst: for client_with_message in recv_data_lst: try: self.process_client_message( get_message(client_with_message), client_with_message) except: logger.info( f'Клиент {client_with_message.getpeername()} отключился от сервера' ) self.clients.remove(client_with_message) # Если есть сообщения, обрабатываем каждое. for message in self.messages: try: self.process_message(message, send_data_lst) except: logger.info( f'Связь с клиентом с именем {message["to"]} была потеряна' ) self.clients.remove(self.names[message['to']]) del self.names[message['to']] self.messages.clear() # Функция адресной отправки сообщения определённому клиенту. Принимает словарь сообщение, список зарегистрированых # пользователей и слушающие сокеты. Ничего не возвращает. def process_message(self, message, listen_socks): if message['to'] in self.names and self.names[ message['to']] in listen_socks: send_message(self.names[message['to']], message) logger.info( f'Отправлено сообщение пользователю {message["to"]} от пользователя {message["from"]}.' ) elif message['to'] in self.names and self.names[ message['to']] not in listen_socks: raise ConnectionError else: logger.error( f'Пользователь {message["to"]} не зарегистрирован на сервере, отправка сообщения невозможна.' ) # Обработчик сообщений от клиентов, принимает словарь - сообщение от клиента, проверяет корректность, отправляет # словарь-ответ в случае необходимости. def process_client_message(self, message, client): logger.debug(f'Разбор сообщения от клиента : {message}') # Если это сообщение о присутствии, принимаем и отвечаем if 'action' in message and message[ 'action'] == 'presence' and 'time' in message and 'user' in message: # Если такой пользователь ещё не зарегистрирован, регистрируем, иначе отправляем ответ и завершаем # соединение. if message['user']['account_name'] not in self.names.keys(): self.names[message['user']['account_name']] = client send_message(client, {'response': 200}) else: response = { 'response': 400, 'error': 'Имя пользователя уже занято' } send_message(client, response) self.clients.remove(client) client.close() return # Если это сообщение, то добавляем его в очередь сообщений. Ответ не требуется. elif 'action' in message and message['action'] == 'message' and 'to' in message and 'time' in message \ and 'from' in message and 'mess_text' in message: self.messages.append(message) return # Если клиент выходит elif 'action' in message and message[ 'action'] == 'exit' and 'account_name' in message: self.clients.remove(self.names['account_name']) self.names['account_name'].close() del self.names['account_name'] return # Иначе отдаём Bad request else: response = {'response': 400, 'error': 'Запрос некорректен'} send_message(client, response) return