def __init__(self, port, ip_address, database, username): # Вызываем конструктор предка threading.Thread.__init__(self) QObject.__init__(self) # Класс База данных - работа с базой self.database = database # Имя пользователя self.username = username # Сокет для работы с сервером self.transport = None # Устанавливаем соединение: self.connection_init(port, ip_address) # Обновляем таблицы известных пользователей и контактов try: self.user_list_update() self.contacts_list_update() except OSError as err: if err.errno: logger.critical(f'Потеряно соединение с сервером.') raise ServerError('Потеряно соединение с сервером!') logger.error( 'Timeout соединения при обновлении списков пользователей.') except json.JSONDecodeError: logger.critical(f'Потеряно соединение с сервером.') raise ServerError('Потеряно соединение с сервером!') # Флаг продолжения работы транспорта. self.running = True
def make_error(file, er=None, id_=None): if er is None: er = ServerError() istr = 'File %s' % file if id_ is not None: istr = '%s, ID %s' % (istr, id_) er.message = '%s, %s' % (istr, er.message) return er
def connection_init(self, port, ip): self.transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.transport.settimeout(5) connected = False for i in range(5): client_logger.info(f'Попытка подключения №{i + 1}') try: self.transport.connect((ip, port)) except (OSError, ConnectionRefusedError): pass else: connected = True break time.sleep(1) if not connected: client_logger.critical( 'Не удалось установить соединение с сервером') raise ServerError('Не удалось установить соединение с сервером') client_logger.debug('Установлено соединение с сервером') passwd_bytes = self.password.encode('utf-8') salt = self.username.lower().encode('utf-8') passwd_hash = hashlib.pbkdf2_hmac('sha512', passwd_bytes, salt, 10000) passwd_hash_string = binascii.hexlify(passwd_hash) client_logger.debug(f'Passwd hash ready: {passwd_hash_string}') pubkey = self.keys.publickey().export_key().decode('ascii') with socket_lock: presense = { ACTION: PRESENCE, TIME: time.time(), USER: { ACCOUNT_NAME: self.username, PUBLIC_KEY: pubkey } } client_logger.debug(f"Presense message = {presense}") try: send_message(self.transport, presense) ans = receive_message(self.transport) client_logger.debug(f'Server response = {ans}.') if RESPONSE in ans: if ans[RESPONSE] == 400: raise ServerError(ans[ERROR]) elif ans[RESPONSE] == 511: ans_data = ans[DATA] hash = hmac.new(passwd_hash_string, ans_data.encode('utf-8'), 'MD5') digest = hash.digest() my_ans = {RESPONSE: 511, DATA: None} my_ans[DATA] = binascii.b2a_base64(digest).decode( 'ascii') send_message(self.transport, my_ans) self.process_server_ans(receive_message( self.transport)) except (OSError, json.JSONDecodeError) as err: client_logger.debug(f'Connection error.', exc_info=err) raise ServerError('Сбой соединения в процессе авторизации.')
def make_error(uploaded_file, er=None, id_=None): if er is None: er = ServerError() istr = 'File %s' % uploaded_file if id_ is not None: istr = '%s, ID %s' % (istr, id_) er.message = '%s, %s' % (istr, er.message) if not er.code: er.code = 500 return er
def __init__(self, *args, **kwargs): """ - self.pars - объект конвертера MoneyConverter() - self.error - объект проверки ввода данных ServerError() - self.response_data - словарь хранит данные для вывода - self.base_data - словарь хранит все базовые данные - self.post_data_dict - словарь хранит данные с POST запроса - self.status - объект хранит данные статусов, описаний и кодов ошибок сервера - self.item_field - словарь хранит дефолтными данными результата работы конвертера :param args: > list() :param kwargs: > dict() """ self.pars = MoneyConverter() self.error = ServerError() self.response_data = bytes() self.base_data = dict() self.post_data_dict = dict() self.status = HTTPStatus.OK self.item_field = dict( Валюта_запроса="Введите конверт. валюту RUB или USD", Сумма_запроса="Введите конверт. сумму", Валюта_ответа="...", Сумма_ответа="..." ) BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
def process_server_ans(self, message): '''Метод обработчик поступающих сообщений с сервера.''' logger.debug(f'Разбор сообщения от сервера: {message}') # Если это подтверждение чего-либо if RESPONSE in message: if message[RESPONSE] == 200: return elif message[RESPONSE] == 400: raise ServerError(f'{message[ERROR]}') elif message[RESPONSE] == 205: self.user_list_update() self.contacts_list_update() self.message_205.emit() else: logger.error( f'Принят неизвестный код подтверждения {message[RESPONSE]}' ) # Если это сообщение от пользователя добавляем в базу, даём сигнал о # новом сообщении elif ACTION in message and message[ACTION] == MESSAGE and SENDER in message and DESTINATION in message \ and MESSAGE_TEXT in message and message[DESTINATION] == self.username: logger.debug( f'Получено сообщение от пользователя {message[SENDER]}:{message[MESSAGE_TEXT]}' ) self.new_message.emit(message)
def process_response_ans(message): logger.debug(f'Разбор приветственного сообщения от сервера: {message}') if 'response' in message: if message['response'] == 200: return '200 : OK' elif message['response'] == 400: raise ServerError(f'400 : {message["error"]}') raise ReqFieldMissingError('response')
def process_response_ans(message): logger.debug(f'Разбор приветственного сообщения от сервера: {message}') if RESPONSE in message: if message[RESPONSE] == 200: return '200 : OK' elif message[RESPONSE] == 400: raise ServerError(f'400 : {message[ERROR]}') raise ReqFieldMissingError(RESPONSE)
def _dispatch_channel(self, method, params): '''Dispatch for xmlrpc methods starting with _channel.''' # Checks for methods existance an non-privacy are done in # RemoteIRCServer._dispatch_channel_method # Get server if len(params) <= 0: raise ServerError('Not enough arguments for method "%s".' % method) server_name = params[0] type_check("server_name", server_name, basestring) if server_name not in self.remote_irc_servers: raise ServerError('Server with name "%s" was not found' % server_name) server = self.remote_irc_servers[server_name] # Dispatch to corresponding server return server._dispatch_channel_method(method, params[1:])
def server_response_processing(message): """Функция обработки ответа от сервера""" LOGGER_CLIENT.debug(f'Сообщение-приветствие от сервера: {message}') if RESPONSE in message: if message[RESPONSE] == 200: return '200 : OK' elif message[RESPONSE] == 400: raise ServerError(f'400 : {message[ERROR]}') raise MissingData(RESPONSE)
def _dispatch(self, method, params): '''Delegate XMLRPC requests to the appropriate method. The method could be in a few different places. Here are the places that are checked, in order: # IRCProxyServer.<method> # If the method name starts with "server_", that prefix is taken off and RemoteIRCServer.<method_stripped> is searched. The first argument is assumed to be the server name, and the method inside the appropriate server is called. # If the method name starts with "channel_", that prefix is taken off and RemoteIRCChannel.<method_stripped> is searched. The first two arguments are assumed to be server name and channel name, and server._dispatch_channel_method is called for the appropriate server. :param method: Name of the XMLRPC method requested. :param params: A tuple of the parameters given in the XMLRPC call. :returns: The return value of the method that was called. An XMLRPC Fault is returned for any errors. ''' #TODO: Double check typechecking in all _dispatch methods. try: # Method inside IRCProxyServer (this instance) func = getattr(self, method, None) if func != None and callable(func): return func(*params) # Look for method inside a RemoteIRCServer instance # Prefix of server_ elif method.startswith("server_"): return self._dispatch_server(method, params) # Look for method inside a RemoteIRCChannel instance # Prefix of channel_ elif method.startswith("channel_") and len(params) > 0: return self._dispatch_channel(method, params) # Method not found! raise ServerError('Method "%s" not found.' % method) except ServerError as e: #TODO: Log raise Fault(2, ' '.join(e.args)) except Exception as e: #TODO: Log traceback.print_exc() raise Fault(3, "Proxy server received an unexpected error. See log file for details.")
def get_events_since(self, start_time): type_check("start_time", start_time, int, float) if start_time < 0: raise ServerError("start_time must be a positive number.") events = self.events.get_events_since(start_time) for server in self.remote_irc_servers.itervalues(): events.extend(server._get_events_since(start_time)) return events
def type_check(var_name, var_value, *var_types): '''Raises a ServerError if var_value's type is not in var_types.''' for var_type in var_types: if isinstance(var_value, var_type): return True raise ServerError('Expected "%s" type for "%s". Got "%s" instead. ' 'Value was: %s"' % (var_type, var_name, type(var_value), var_value))
def import_event_json(zip_path): """ Imports and creates event from json zip """ path = 'static/temp/import_event' # delete existing files if os.path.isdir(path): shutil.rmtree(path, ignore_errors=True) # extract files from zip with zipfile.ZipFile(zip_path, "r") as z: z.extractall('static/temp/import_event') # create event data = json.loads(open(path + '/event.json', 'r').read()) _, data = _trim_id(data) data = _delete_fields(('event', EventDAO), data) new_event = EventDAO.create(data, 'dont')[0] # create other services try: service_ids = {} for item in IMPORT_SERIES: data = open(path + '/%s.json' % item[0], 'r').read() dic = json.loads(data) changed_ids = create_service_from_json(dic, item, new_event.id, service_ids) service_ids[item[0]] = changed_ids.copy() except BaseError as e: EventDAO.delete(new_event.id) raise e except Exception: EventDAO.delete(new_event.id) raise ServerError() custom_form = CustomForms( event_id=new_event.id, session_form= '{"title":{"include":1,"require":1},"subtitle":{"include":0,"require":0},' '"short_abstract":{"include":1,"require":0},"long_abstract":{"include":0,' '"require":0},"comments":{"include":1,"require":0},"track":{"include":0,' '"require":0},"session_type":{"include":0,"require":0},"language":{"include":0,' '"require":0},"slides":{"include":1,"require":0},"video":{"include":0,' '"require":0},"audio":{"include":0,"require":0}}', speaker_form= '{"name":{"include":1,"require":1},"email":{"include":1,"require":1},' '"photo":{"include":1,"require":0},"organisation":{"include":1,' '"require":0},"position":{"include":1,"require":0},"country":{"include":1,' '"require":0},"short_biography":{"include":1,"require":0},"long_biography"' ':{"include":0,"require":0},"mobile":{"include":0,"require":0},' '"website":{"include":1,"require":0},"facebook":{"include":0,"require":0},' '"twitter":{"include":1,"require":0},"github":{"include":0,"require":0},' '"linkedin":{"include":0,"require":0}}') save_to_db(custom_form, "Custom form saved") return new_event
def process_ans(message): ''' Функция разбирает ответ сервера ''' LOGGER_CLIENT.debug(f'Разбор приветственного сообщения от сервера: {message}') if RESPONSE in message: if message[RESPONSE] == 200: return '200 : OK' elif message[RESPONSE] == 400: raise ServerError(f'400 : {message[ERROR]}') raise ReqFieldMissingError(RESPONSE)
def server_disconnect(self, server_name, part_message=""): type_check("server_name", server_name, basestring) type_check("part_message", part_message, basestring) if server_name not in self.remote_irc_servers: raise ServerError('Server with name="%s" does not exist' % server_name) server = self.remote_irc_servers[server_name] server._disconnect(part_message) del self.remote_irc_servers[server_name] self.events.append(type="server_disconnect", server=server_name) return True
def process_response_ans(message): """ Функция разбирает ответ сервера на сообщение о присутствии, возращает 200 если все ОК или генерирует исключение при ошибке """ LOGGER.debug(f'Разбор приветственного сообщения от сервера: {message}') if RESPONSE in message: if message[RESPONSE] == 200: return '200 : OK' elif message[RESPONSE] == 400: raise ServerError(f'400 : {message[ERROR]}') raise ReqFieldMissingError(RESPONSE)
def connection_init(self, port, ip): # Инициализация сокета и сообщение серверу о нашем появлении self.transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Таймаут необходим для освобождения сокета. self.transport.settimeout(5) # Соединяемся, 5 попыток соединения, флаг успеха ставим в True если # удалось connected = False for i in range(2): logger.info(f'Попытка подключения №{i + 1}') try: self.transport.connect((ip, port)) except (OSError, ConnectionRefusedError): pass else: connected = True break time.sleep(1) # Если соединится не удалось - исключение if not connected: logger.critical('Не удалось установить соединение с сервером') raise ServerError('Не удалось установить соединение с сервером') logger.debug('Установлено соединение с сервером') # Посылаем серверу приветственное сообщение и получаем ответ что всё # нормально или ловим исключение. try: with socket_lock: send_message(self.transport, self.create_presence()) self.process_server_ans(get_my_message(self.transport)) except (OSError, json.JSONDecodeError): logger.critical('Потеряно соединение с сервером!') raise ServerError('Потеряно соединение с сервером!') # Раз всё хорошо, сообщение о установке соединения. logger.info('Соединение с сервером успешно установлено.')
def ans_handling(message): """ Процессинг ответа от сервера :param message: :return: """ logger.debug(f'Расшифровка ответа от сервера: {message}') if RESPONSE in message: if message[RESPONSE] == 200: return '200 : OK' elif message[RESPONSE] == 400: raise ServerError(f'400 : {message[ERROR]}') raise ReqFieldMissingError(RESPONSE)
def process_response_answer(my_msg): """ Данный метод разбирает ответ сервера на сообщение о присутствии. Функция возращает 200 если все ОК или генерирует исключение при ошибке """ CLIENT_LOGGER.debug( f'Разбор приветственного сообщения от сервера: {my_msg}') if RESPONSE in my_msg: if my_msg[RESPONSE] == 200: return '200 : OK' elif my_msg[RESPONSE] == 400: raise ServerError(f'400 : {my_msg[ERROR]}') raise ReqFieldMissingError(RESPONSE)
def _dispatch_server(self, method, params): '''Dispatch for xmlrpc methods starting with _server.''' # Check for method existence and callability server_method = method[len("server_"):] if not server_method.startswith("_") and \ callable(getattr(RemoteIRCServer, server_method, None)): # Get server if len(params) <= 0: raise ServerError('Not enough arguments for method "%s".' % method) server_name = params[0] type_check("server_name", server_name, basestring) if server_name not in self.remote_irc_servers: raise ServerError('Server with name "%s" was not found' % server_name) server = self.remote_irc_servers[server_name] # Call server method func = getattr(server, server_method) return func(*params[1:]) raise ServerError('Method "%s" not found.' % method)
def server_connect(self, server_name, nick_name, uri, port=6667, password="", ssl=False, ipv6=False): type_check("server_name", server_name, basestring) type_check("nick_name", nick_name, basestring) type_check("uri", uri, basestring) type_check("port", port, int) type_check("password", password, basestring) type_check("ssl", ssl, bool) type_check("ipv6", ipv6, bool) if port < 0 or port > 65535: raise ServerError("port must be between 0 and 65535 inclusive.") if not password: password = None if server_name in self.server_list(): raise ServerError("Server with that name is already connected!") connection = self.irc_client.server() remote_server = RemoteIRCServer(connection, server_name, nick_name, uri, port, password, ssl, ipv6) self.remote_irc_servers[server_name] = remote_server self.events.append(type="server_connect", server=server_name) return True
def process_response_ans(message): """ Функция разбирает ответ сервера на сообщение о присутствии, возращает 200 если все ОК или генерирует исключение при ошибке :param message: :return: """ print(f"Разбор приветственного сообщения от сервера: {message}") if RESPONSE in message: if message[RESPONSE] == 200: return "200 : OK" elif message[RESPONSE] == 400: raise ServerError(f"400 : {message[ERROR]}") raise ReqFieldMissingError(RESPONSE)
def main(): # client.py -a 192.168.1.2 -p 8079 -m send port, host, name = parce_command_line() if not name: name = input('Введите имя пользователя: ') LOGGER.info(f'Запущено клиентское приложение. IP-адрес сервера: {host},' f' порт сервера: {port}, имя пользователя: {name}.') try: client = Client(name, port, host) client.connect() client.send_presence_message() answer = client.get_message() LOGGER.info( f'Установлено соединение с сервером. Ответ сервера: {answer}') if answer['response'] >= 400: raise ServerError(f'400 : {answer["error"]}') except json.JSONDecodeError: LOGGER.error('Не удалось декодировать полученную Json строку.') sys.exit(1) except ServerError as error: LOGGER.error( f'При установке соединения сервер вернул ошибку: {error.text}') pass except ReqFieldMissingError as missing_error: LOGGER.error( f'В ответе сервера отсутствует необходимое поле {missing_error.missing_field}' ) sys.exit(1) except ConnectionRefusedError: LOGGER.critical(f'Не удалось подключиться к серверу {host}:{port}, ' f'конечный компьютер отверг запрос на подключение.') sys.exit(1) else: # Если соединение с сервером установлено корректно, запускаем процесс приема сообщений #Запуск потока на получение сообщения receiver = Thread(target=client.run_listern_mode) receiver.daemon = True receiver.start() # Запуск потока на отправление сообщения user_interface = Thread(target=client.interact_with_user) user_interface.daemon = True user_interface.start() # Если один из потоков завершён, значит или потеряно соединение или пользователь # ввёл exit. Т.к. все события обработываются в потоках, достаточно завершить цикл. while True: sleep(1) if receiver.is_alive() and user_interface.is_alive(): continue break
def __init__(self, port, ip_address, database, username, passwd, keys): threading.Thread.__init__(self) QObject.__init__(self) self.database = database self.username = username self.password = passwd self.transport = None self.keys = keys self.connection_init(port, ip_address) try: self.user_list_update() self.contacts_list_update() except OSError as err: if err.errno: client_logger.critical(f'Потеряно соединение с сервером.') raise ServerError('Потеряно соединение с сервером!') client_logger.error( 'Timeout соединения при обновлении списков пользователей.') except json.JSONDecodeError: client_logger.critical(f'Потеряно соединение с сервером.') raise ServerError('Потеряно соединение с сервером!') self.running = True
def remove_contact(sock, username, contact): logger.debug(f'Создание контакта {contact}') req = { ACTION: REMOVE_CONTACT, TIME: time.time(), USER: username, ACCOUNT_NAME: contact } send_message(sock, req) ans = get_message(sock) if RESPONSE in ans and ans[RESPONSE] == 200: pass else: raise ServerError('Ошибка удаления клиента') print('Удачное удаление')
def remove_contact(sock, username, contact): logger.debug(f'Создание контакта {contact}') req = { 'action': 'remove', 'time': time.time(), 'user': username, 'account_name': contact } send_message(sock, req) ans = get_message(sock) if 'response' in ans and ans['response'] == 200: pass else: raise ServerError('Ошибка удаления клиента') print('Удачное удаление')
def add_contact(sock, username, contact): LOGGER.debug(f'Создание контакта {contact}') req = { ACTION: ADD_CONTACT, TIME: time.time(), USER: username, ACCOUNT_NAME: contact } send_message(sock, req) ans = get_my_message(sock) if RESPONSE in ans and ans[RESPONSE] == 200: pass else: raise ServerError('Ошибка создания контакта') print('Удачное создание контакта.')
def import_event_json(zip_path): """ Imports and creates event from json zip """ global CUR_ID path = 'static/temp/import_event' # delete existing files if os.path.isdir(path): shutil.rmtree(path, ignore_errors=True) # extract files from zip with zipfile.ZipFile(zip_path, "r") as z: z.extractall('static/temp/import_event') # create event try: data = json.loads(open(path + '/event.json', 'r').read()) _, data = _trim_id(data) data = _delete_fields(('event', EventDAO), data) new_event = EventDAO.create(data, 'dont')[0] except BaseError as e: raise make_error('event', er=e) except Exception: raise make_error('event') # create other services try: service_ids = {} for item in IMPORT_SERIES: data = open(path + '/%s.json' % item[0], 'r').read() dic = json.loads(data) changed_ids = create_service_from_json(dic, item, new_event.id, service_ids) service_ids[item[0]] = changed_ids.copy() CUR_ID = None except BaseError as e: EventDAO.delete(new_event.id) raise make_error(item[0], er=e, id_=CUR_ID) except IOError: EventDAO.delete(new_event.id) raise NotFoundError('File %s.json missing in event zip' % item[0]) except ValueError: EventDAO.delete(new_event.id) raise make_error(item[0], er=ServerError('Invalid json')) except Exception: EventDAO.delete(new_event.id) raise make_error(item[0], id_=CUR_ID) # return return new_event
def import_event_task(self, file): """Import Event Task""" task_id = self.request.id.__str__() # str(async result) try: result = import_event_task_base(self, file) update_import_job(task_id, result['id'], 'SUCCESS') # return item except BaseError as e: print traceback.format_exc() update_import_job(task_id, e.message, e.status) result = {'__error': True, 'result': e.to_dict()} except Exception as e: print traceback.format_exc() update_import_job(task_id, e.message, e.status) result = {'__error': True, 'result': ServerError().to_dict()} # send email send_import_mail(task_id, result) # return result return result