Exemplo n.º 1
0
    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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
    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('Сбой соединения в процессе авторизации.')
Exemplo n.º 4
0
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
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
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')
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
    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:])
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
    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.")
Exemplo n.º 12
0
    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
Exemplo n.º 13
0
Arquivo: tools.py Projeto: afcarl/pirc
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))
Exemplo n.º 14
0
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
Exemplo n.º 15
0
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)
Exemplo n.º 16
0
    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)
Exemplo n.º 18
0
    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('Соединение с сервером успешно установлено.')
Exemplo n.º 19
0
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)
Exemplo n.º 20
0
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)
Exemplo n.º 21
0
    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)
Exemplo n.º 22
0
    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
Exemplo n.º 23
0
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)
Exemplo n.º 24
0
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
Exemplo n.º 25
0
    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
Exemplo n.º 26
0
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('Удачное удаление')
Exemplo n.º 27
0
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('Удачное удаление')
Exemplo n.º 28
0
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
Exemplo n.º 30
0
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