def read_sock_streams(self, sock_to_read, clients, timeout=0.5): """ Метод для чтения из сокета приходящие сообщения от клиента :param sock_to_read: список сокетов, ожидающие в очереди на чтение :param timeout: таймоут для клиентского сокета :param clients: список всех сокетов """ for sock in sock_to_read: sock.settimeout(timeout) m = JIMResponse() try: m.rcv_message(sock) if m.list_of_dicts: for i in m.list_of_dicts: print(i) self._put_to_que(i, sock, clients) else: self._put_to_que(m.dict_message, sock, clients) # action = m.get_message_action() # print(action) # input_q.put({'action': action, 'sock': sock, 'clients': clients, 'text': m.dict_message}) except (ClosedSocketError, ConnectionResetError, ConnectionAbortedError): # если выходит ошибка, значит клиент вышел, не разорвав соединение, удаляем сокет из списка клиентов self._remove_bad_client_sock(sock, clients)
def data_received(self, data): print(data) try: self.message = JIMResponse(data) except: # не получается отловить exception в другом, не асинхронном модуле jim_v2.py. self.message = JIMResponse() self.message.encoded_message = data self.message.decode_to_few_messages() if self.message.list_of_dicts: for i in self.message.list_of_dicts: self.message.dict_message = i self.pass_to_handler() else: self.pass_to_handler()
def __init__(self, hostname='localhost', port=7777): self.def_hostname = hostname self.def_port = port # read_ и write_ нужны для проверки, если клиент был запущен из консоли только в одном режиме self._read = False self._write = False self.alive = True self.hostname, self.port = self._cli_param_get() self.username = '' self.client_db = None self.img_parts = {} self.m = JIMMessage() self.m_r = JIMResponse() self.sock = self.open_client_socket() self.img_sender = ImageWorker(self.sock, self.m, self.img_parts)
class ServerProtocol(asyncio.Protocol): def __init__(self, db, img_parts, clients): self.server_db = db self.img_parts = img_parts self.clients = clients self.action = None self.message = None self.socket = None self.transport = None def connection_made(self, transport): self.socket = transport.get_extra_info('socket') self.transport = transport def data_received(self, data): print(data) try: self.message = JIMResponse(data) except: # не получается отловить exception в другом, не асинхронном модуле jim_v2.py. self.message = JIMResponse() self.message.encoded_message = data self.message.decode_to_few_messages() if self.message.list_of_dicts: for i in self.message.list_of_dicts: self.message.dict_message = i self.pass_to_handler() else: self.pass_to_handler() def pass_to_handler(self): self.action = self.message.dict_message[ACTION] print(self.message) self.handle_request() def connection_lost(self, exc): self.clients.remove(self.socket) def handle_request(self): if self.action == AUTH: self._auth_handle() elif self.action == MSG: self._msg_handle() elif self.action == PRESENCE: self._presence_handle() elif self.action == GET_CONTACTS: self._get_contacts_handle() elif self.action == GET_CONTACT_IMG: print('Запрос изображений') self._get_contact_img_handle() elif self.action == ADD_CONTACT: self._add_del_contact_handle() elif self.action == DEL_CONTACT: self._add_del_contact_handle(False) elif self.action == JOIN: self._join_handle() elif self.action == LEAVE: self._leave_handle() elif self.action == REGISTER: self._register_handle() elif self.action == IMG or self.action == IMG_PARTS: img_worker = ImageWorker(self.socket, self.message, self.img_parts) img_worker.handle(self.action) self._whole_message_check(img_worker) else: self.message.response_message_create(code=WRONG_REQUEST, send_message=False) self.transport.write(self.message.encoded_message) def _auth_handle(self): client_name = self.message.dict_message[USER][ACCOUNT_NAME] client = self.server_db.request_client(client_name) if client is None: self.message.response_message_create( code=NOT_FOUND, message_text="Пользователь не существует", send_message=False) else: client_hash = self.message.dict_message[USER][PASSWORD] if client.hash[0].hashpass == client_hash: print('{} авторизован'.format(client_name)) self.clients.append(self.socket) self.message.response_message_create(code=OK, send_message=False) else: print('{} не авторизован'.format(client_name)) self.message.response_message_create(code=WRONG_COMBINATION, send_message=False) self.transport.write(self.message.encoded_message) def _msg_handle(self): if '#' in self.message.dict_message[TO]: # print('chat') room = self.message.dict_message[TO][1:] contacts = self.server_db.get_room_members(room) for contact in contacts: if contact != self.message.dict_message[FROM]: sockets = self.server_db.get_client_sockets(contact) for sock_fn in sockets: for sock_online in self.clients: if sock_fn == sock_online.fileno(): self.message.send_message(sock_online) # self.transport.sendto(self.message.encoded_message, sock_online) else: # print(self.message.dict_message) sockets = self.server_db.get_client_sockets( self.message.dict_message[TO]) for sock_fn in sockets: for sock_online in self.clients: if sock_fn == sock_online.fileno(): self.message.send_message(sock_online) # self.transport.sendto(self.message.encoded_message, sock_online) print('Сообщение отправлено!') self.message.response_message_create(OK, send_message=False) self.transport.write(self.message.encoded_message) def _presence_handle(self): username = self.message.dict_message[USER][ACCOUNT_NAME] client = self.server_db.request_client(username) if client is None: self.message.response_message_create( code=NOT_FOUND, message_text='Пользователь не найден', send_message=False) else: self.server_db.add_to_history(username, self.message.dict_message[TIME], self.socket.getpeername()[0]) self.server_db.add_online_client(username, self.socket.fileno()) self.message.response_message_create(self.socket, OK, send_message=False) self.transport.write(self.message.encoded_message) def _get_contacts_handle(self): client = self.server_db.ident_client_by_sockets(self.socket.fileno()) contacts_quantity = self.server_db.count_contacts(client) contacts = self.server_db.get_all_contacts(client) self.message.response_message_create(code=ACCEPTED, quantity=contacts_quantity, send_message=False) self.transport.write(self.message.encoded_message) contact_info_message = JIMMessage() for contact in contacts: contact_info_message.create_server_contact_list(contact.login) self.transport.write(contact_info_message.encoded_message) def _get_contact_img_handle(self): contact_name = self.message.dict_message[USER_ID] client = self.server_db.request_client(contact_name) if client: img = self.server_db.get_client_img(contact_name) img_message = JIMMessage() img_sender = ImageWorker(self.socket, img_message, self.img_parts) img_sender.img_send(img.img_base64, contact_name) def _add_del_contact_handle(self, add=True): new_user = self.message.dict_message[USER_ID] if self.server_db.request_client(new_user) is None: self.message.response_message_create(NOT_FOUND, with_message=False, send_message=False) else: client = self.server_db.ident_client_by_sockets( self.socket.fileno()) if client: if new_user not in self.server_db.get_all_contacts(client): if add: self.server_db.add_contacts(client, new_user) else: self.server_db.del_contact(client, new_user) self.message.response_message_create(OK, with_message=False, send_message=False) else: self.message.response_message_create(WRONG_REQUEST, with_message=False, send_message=False) else: print('Клиента с таким сокетом не существует') self.message.response_message_create( WRONG_REQUEST, message_text='Сокет не зарегистрирован', send_message=False) self.transport.write(self.message.encoded_message) def _register_handle(self): client_name = self.message.dict_message[USER][ACCOUNT_NAME] pswd = self.message.dict_message[USER][PASSWORD] # проверяем, если клиент с таким именем уже не зарегистрирован в нашем мессенджере client = self.server_db.request_client(client_name) if client is None: self.server_db.add_client(client_name, "Yep, i'm here") hash_ = get_safe_hash(pswd, SALT) self.server_db.register_new_hash(client_login=client_name, hash_=hash_) self.message.response_message_create(OK, send_message=False) else: self.message.response_message_create( code=CONFLICT, with_message=True, message_text="Account is in use", send_message=False) self.transport.write(self.message.encoded_message) def _leave_handle(self): room_name = self.message.dict_message[ROOM] client = self.server_db.ident_client_by_sockets(self.socket.fileno()) room = self.server_db.request_room(room_name) if room and client: self.server_db.join_leave_room(room_name, client) self.message.response_message_create(OK, True, 'Вы покинули чат', send_message=False) else: # print('Данной комнаты не существует') self.message.response_message_create( WRONG_REQUEST, True, 'Данной комнаты не существует', send_message=False) self.transport.write(self.message.encoded_message) def _join_handle(self): room_name = self.message.dict_message[ROOM] client = self.server_db.ident_client_by_sockets(self.socket.fileno()) room = None while not room: room = self.server_db.request_room(room_name) if room: self.server_db.join_leave_room(room_name, client) self.message.response_message_create( OK, True, 'Вы успешно присоединились к чату', send_message=False) else: self.server_db.add_room(room_name) self.transport.write(self.message.encoded_message) def _whole_message_check(self, img_worker): if img_worker.whole_received_img: if self.server_db.get_client_img( img_worker.whole_received_img[USER_ID]) is None: self.server_db.write_client_img( img_worker.whole_received_img[USER_ID], img_worker.whole_received_img[IMG]) else: self.server_db.update_client_img( img_worker.whole_received_img[USER_ID], img_worker.whole_received_img[IMG])
def _get_from_queue(self): item = self.queue.get() self.message = JIMResponse(item['text']) self.action = item['action'] self.sock = item['sock'] self.clients = item['clients']
def _put_to_que(dict_msg, sock, clients): m = JIMResponse(dict_msg) action = m.get_message_action() input_q.put({'action': action, 'sock': sock, 'clients': clients, 'text': m.dict_message})
class Handler(Thread): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) print('Инициализация') self.queue = input_q self.message = None self.action = None self.sock = None self.clients = None self.active = True self.img_worker = None self.img_parts = {} def _get_from_queue(self): item = self.queue.get() self.message = JIMResponse(item['text']) self.action = item['action'] self.sock = item['sock'] self.clients = item['clients'] def handling_action(self): if self.action == PRESENCE: self._presence_handle() elif self.action == MSG: self._msg_handle() elif self.action == GET_CONTACTS: self._get_contacts_handle() elif self.action == GET_CONTACT_IMG: print('Запрос изображений') elif self.action == ADD_CONTACT: self._add_del_contact_handle() elif self.action == DEL_CONTACT: self._add_del_contact_handle(False) elif self.action == JOIN: self._join_handle() elif self.action == LEAVE: self._leave_handle() elif self.action == AUTH: self._auth_handle() elif self.action == REGISTER: self._register_handle() elif self.action == IMG or self.action == IMG_PARTS: self.img_worker = ImageWorker(self.sock, self.message, self.img_parts) self.img_worker.handle(self.action) self._whole_message_check() else: self.message.response_message_create(self.sock, WRONG_REQUEST) # TODO сделать проще... как можно восстановить сокет из fd? def _msg_handle(self): if '#' in self.message.dict_message[TO]: # print('chat') room = self.message.dict_message[TO][1:] contacts = server_db.get_room_members(room) for contact in contacts: if contact != self.message.dict_message[FROM]: sockets = server_db.get_client_sockets(contact) for sock_ in sockets: for sock_online in self.clients: if sock_ == sock_online.fileno(): self.message.send_message(sock_online) else: print(self.message.dict_message) sockets = server_db.get_client_sockets(self.message.dict_message[TO]) for sock_ in sockets: for sock_online in self.clients: if sock_ == sock_online.fileno(): self.message.send_message(sock_online) print('Сообщение отправлено!') self.message.response_message_create(self.sock, OK) def _auth_handle(self): client_name = self.message.dict_message[USER][ACCOUNT_NAME] client = server_db.request_client(client_name) if client is None: self.message.response_message_create(self.sock, NOT_FOUND, message_text="Пользователь не существует") else: client_hash = self.message.dict_message[USER][PASSWORD] if client.hash[0].hashpass == client_hash: print('{} авторизован'.format(client_name)) self.message.response_message_create(self.sock, OK) else: print('{} не авторизован'.format(client_name)) self.message.response_message_create(self.sock, WRONG_COMBINATION, message_text='') def _register_handle(self): client_name = self.message.dict_message[USER][ACCOUNT_NAME] pswd = self.message.dict_message[USER][PASSWORD] # проверяем, если клиент с таким именем уже не зарегистрирован в нашем мессенджере client = server_db.request_client(client_name) if client is None: server_db.add_client(client_name, "Yep, i'm here") hash_ = get_safe_hash(pswd, SALT) print(hash_) server_db.register_new_hash(client_login=client_name, hash_=hash_) self.message.response_message_create(self.sock, OK) else: self.message.response_message_create(self.sock, code=CONFLICT, with_message=True, message_text="Account is in use", send_message=True) def _leave_handle(self): room_name = self.message.dict_message[ROOM] client = server_db.ident_client_by_sockets(self.sock.fileno()) room = server_db.request_room(room_name) if room and client: server_db.join_leave_room(room_name, client) self.message.response_message_create(self.sock, 200, True, 'Вы покинули чат') else: # print('Данной комнаты не существует') self.message.response_message_create(self.sock, 400, True, 'Данной комнаты не существует') def _join_handle(self): room_name = self.message.dict_message[ROOM] client = server_db.ident_client_by_sockets(self.sock.fileno()) room = None while not room: room = server_db.request_room(room_name) if room: server_db.join_leave_room(room_name, client) self.message.response_message_create(self.sock, 200, True, 'Вы успешно присоединились к чату') else: server_db.add_room(room_name) def _presence_handle(self): username = self.message.dict_message[USER][ACCOUNT_NAME] client = server_db.request_client(username) if client is None: self.message.response_message_create(self.sock, NOT_FOUND, message_text='Пользователь не найден') else: server_db.add_to_history(username, self.message.dict_message[TIME], self.sock.getpeername()[0]) server_db.add_online_client(username, self.sock.fileno()) self.message.response_message_create(self.sock, OK) def _get_contacts_handle(self): client = server_db.ident_client_by_sockets(self.sock.fileno()) # print (client) contacts_quantity = server_db.count_contacts(client) contacts = server_db.get_all_contacts(client) self.message.response_message_create(sock=self.sock, code=ACCEPTED, quantity=contacts_quantity) contact_info_message = JIMMessage() for contact in contacts: contact_info_message.create_server_contact_list(contact.login) contact_info_message.send_message(self.sock) # time.sleep(0.3) def _add_del_contact_handle(self, add=True): new_user = self.message.dict_message[USER_ID] if server_db.request_client(new_user) is None: self.message.response_message_create(self.sock, NOT_FOUND, with_message=False) else: client = server_db.ident_client_by_sockets(self.sock.fileno()) if client: # print(client) if new_user not in server_db.get_all_contacts(client): if add: server_db.add_contacts(client, new_user) else: server_db.del_contact(client, new_user) self.message.response_message_create(self.sock, OK, with_message=False) else: self.message.response_message_create(self.sock, WRONG_REQUEST, with_message=False) else: print('Клиента с таким сокетом не существует') self.message.response_message_create(self.sock, WRONG_REQUEST, message_text='Сокет не зарегистрирован') def _whole_message_check(self): if self.img_worker.whole_received_img: if server_db.get_client_img(self.img_worker.whole_received_img[USER_ID]) is None: server_db.write_client_img(self.img_worker.whole_received_img[USER_ID], self.img_worker.whole_received_img[IMG]) else: server_db.update_client_img(self.img_worker.whole_received_img[USER_ID], self.img_worker.whole_received_img[IMG]) def run(self): print("i'm running") while True: if not self.queue.empty(): self._get_from_queue() self.handling_action() if not self.active: break return
class Client(metaclass=ClientVerifier): """ Класс представлен необходимыми методами и свойствами для работы клиента. Метаклассом для этого класса послужил ClientVerifier, выполняющий функцию проверки используемых методов в данном классе. При инициализации экземпляра класса, передаются значения удалённого хоста и порт сервера, с которым будет осуществлять взаимодействия """ def __init__(self, hostname='localhost', port=7777): self.def_hostname = hostname self.def_port = port # read_ и write_ нужны для проверки, если клиент был запущен из консоли только в одном режиме self._read = False self._write = False self.alive = True self.hostname, self.port = self._cli_param_get() self.username = '' self.client_db = None self.img_parts = {} self.m = JIMMessage() self.m_r = JIMResponse() self.sock = self.open_client_socket() self.img_sender = ImageWorker(self.sock, self.m, self.img_parts) def _cli_param_get(self): """ Установить значение порта и адреса исходя из переданных данных, при запуске через командную строку :return: """ try: port = int(find_cli_key_and_argument('-p', self.def_port)) except ValueError: raise WrongPortError addr = find_cli_key_and_argument('-a', self.def_hostname) self._read = '-r' in sys.argv self._write = '-w' in sys.argv return addr, port def open_client_socket(self): """ Создаёт экземпляр класса socket для клиентского приложения """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((self.hostname, self.port)) except ConnectionRefusedError: raise ConnectionRefusedError("Соединение по {}:{} не возможно".format(self.hostname, self.port)) return sock @staticmethod def user_credentials_req(): usr = input('Имя пользователя: ') pswd = input('Пароль: ') return usr, pswd def authorization(self, usr='', pswd=''): pswd_hash = get_safe_hash(pswd, SALT) self.m.create_auth_reg_message(usr, pswd_hash) self.m.send_rcv_message(self.sock) resp = self.m.dict_message[RESPONSE] # print(resp) if resp == OK: print("{} авторизован, приятного пользования".format(usr)) auth_confirm = True # return "{} авторизован, приятного пользования".format(usr) elif resp == WRONG_COMBINATION: print("Не верный логин или пароль") auth_confirm = False # return "Не верный логин или пароль" else: print("Пользователя не существует") auth_confirm = False if not auth_confirm: print('Попробуйте ещё раз') return auth_confirm def registration(self, usr='', pswd=''): self.m.create_auth_reg_message(usr, pswd, registration=True) self.m.send_rcv_message(self.sock) resp = self.m.dict_message[RESPONSE] if resp == OK: print('Вы зарегистрировались, приятного пользования') reg = True elif resp == CONFLICT: print('Пользователь с такими именем уже существует') reg = False else: print('Регистрация не удалась') reg = False if not reg: print('Попробуйте ещё раз') return reg def start_client(self, usr="", pswd="", status="I'm here"): if not usr: reg = False while not reg: ans = input('Вы зарегистрированны? y/n: ') ans = ans.upper() if ans == 'N': usr, pswd = self.user_credentials_req() reg = self.registration(usr, pswd) elif ans == 'Y': reg = True auth = False while not auth: usr, pswd = self.user_credentials_req() auth = self.authorization(usr, pswd) self.username = usr # получаем доступ к принадлежащй данному клиенту базе данных self.client_db = ClientWorker('sqlite:///system/db/{}_client_db.db?check_same_thread=False'. format(self.username)) self.m.create_presence_message(usr, status) self.m.send_rcv_message(self.sock) self.receive_contact_messages() def receive_contact_messages(self): """ В связи с тем, что контакт_сообщения могут приходить подряд, в этом случае, они будут декодированы и упакованы в список. Поэтому после получения сообщения мы проверяем, если список не пустой, т.о. понимаем, что сообщений было несколько. """ message_lock.acquire() self.m.create_get_contact_message() print(self.m.send_rcv_message(self.sock)) quantity = self.m.dict_message[QUANTITY] rcvd_qtty = 0 while quantity != rcvd_qtty: self.m.rcv_message(self.sock) if self.m.list_of_dicts: n = len(self.m.list_of_dicts) for dict_ in self.m.list_of_dicts: self.add_contact_to_db(dict_) else: self.add_contact_to_db(self.m.dict_message) n = 1 rcvd_qtty += n message_lock.release() def add_contact_to_db(self, dict_message): try: # Contacts(dict_message[USER_ID]).save() self.client_db.add_contact(dict_message[USER_ID]) except sqlalchemy.exc.IntegrityError: print('Клиент уже есть') def get_all_contacts(self): self.client_db.session.rollback() return self.client_db.get_all_contacts() def get_contact_img(self, contact_name='basic_user'): self.m.create_get_contact_img_message(contact_name) self.m.send_message(self.sock) # self.m.rcv_message(self.sock) def change_contact_global(self, username='******', add=True): message_lock.acquire() self.m.create_change_contact_message(username, add=add) self.m.send_rcv_message(self.sock) print(self.m.dict_message) if self.m.dict_message[RESPONSE] == 200: ok = True else: ok = False message_lock.release() return ok def add_contact_local(self, contact='MUSEUN'): self.client_db.add_contact(contact) def del_contact_local(self, contact='MUSEUN'): self.client_db.del_contact(contact) def check_local_contact(self, contact=''): if contact in self.client_db.get_all_contacts(): ok = True else: ok = False return ok def send_msg_message(self, to, from_, text): message_lock.acquire() self.m.create_msg_message(False, to, from_, text) self.client_db.add_to_history(to, time.ctime(), text, True) self.m.send_rcv_message(self.sock) message_lock.release() def load_messages_from_history(self, contact=''): return self.client_db.get_messages_from_history(contact) def cycle_read_messages(self, queue): while self.alive: wait = 0.5 r, w, e = select.select([self.sock], [self.sock], [], wait) for sock_ in r: self.m_r.rcv_message(sock_) if self.m_r.list_of_dicts: for dict_ in self.m_r.list_of_dicts: self.m_r.dict_message = dict_ self.received_message_handle() else: self.received_message_handle() # if self.m_r.dict_message[ACTION] == MSG: # self.client_db.session.rollback() # self.client_db.add_to_history(self.m_r.dict_message[FROM], time.ctime(), # self.m_r.dict_message[MESSAGE], False) # print(self.m_r.dict_message) # # queue.put(self.m_r.dict_message) # self.m_r.clean_buffer() # elif self.m_r.dict_message[ACTION] == IMG or self.m_r.dict_message[ACTION] == IMG_PARTS: # img_receiver = ImageWorker(self.sock, self.m_r, self.img_parts) # img_receiver.handle(self.m_r.dict_message[ACTION]) def received_message_handle(self): if self.m_r.dict_message[ACTION] == MSG: self.client_db.session.rollback() self.client_db.add_to_history(self.m_r.dict_message[FROM], time.ctime(), self.m_r.dict_message[MESSAGE], False) print(self.m_r.dict_message) # queue.put(self.m_r.dict_message) self.m_r.clean_buffer() elif self.m_r.dict_message[ACTION] == IMG or self.m_r.dict_message[ACTION] == IMG_PARTS: img_receiver = ImageWorker(self.sock, self.m_r, self.img_parts) img_receiver.handle(self.m_r.dict_message[ACTION]) def cli_interact(self): while self.alive: action = input('>>') if action == 'send': to_ = input('>>Кому отправить: ') text = input('>>Текст сообщения: ') self.send_msg_message(to=to_, from_=self.username, text=text) pass elif action == 'show': for i in self.get_all_contacts(): print(i) elif action == 'add': new = input('>>Введите имя контакта: ') if not self.check_local_contact(new): if self.change_contact_global(new): self.add_contact_local(new) print('Клиент добавлен') else: print('Не удаётся добавить клиента') elif action == 'del': del_ = input('>>Введите имя контакта: ') if self.check_local_contact(del_): if self.change_contact_global(del_, False): self.del_contact_local(del_) print('Клиент удален') else: print('Не удаётся удалить клиента') elif action == 'img': base64_to_send = input('>>Введите base64 код для отправки: ') # img_sender = ImageWorker(self.sock, self.m, self.img_parts) self.img_sender.img_send(base64_to_send) elif action == 'get_img': contact_name = input('>>Введите имя для получения изображения: ') self.get_contact_img(contact_name) elif action == 'end': self.alive = False break else: print('Не верное действие')