|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| import json
|
| import random
|
| import time
|
| from functools import wraps
|
| from io import BytesIO
|
| from flask import (
|
| Response, jsonify, send_file, make_response,
|
| request as flask_request,
|
| )
|
| from werkzeug.http import HTTP_STATUS_CODES
|
|
|
| from api.utils import json_dumps
|
| from api.settings import RetCode
|
| from api.settings import (
|
| REQUEST_MAX_WAIT_SEC, REQUEST_WAIT_SEC,
|
| stat_logger, CLIENT_AUTHENTICATION, HTTP_APP_KEY, SECRET_KEY
|
| )
|
| import requests
|
| import functools
|
| from api.utils import CustomJSONEncoder
|
| from uuid import uuid1
|
| from base64 import b64encode
|
| from hmac import HMAC
|
| from urllib.parse import quote, urlencode
|
|
|
|
|
| requests.models.complexjson.dumps = functools.partial(
|
| json.dumps, cls=CustomJSONEncoder)
|
|
|
|
|
| def request(**kwargs):
|
| sess = requests.Session()
|
| stream = kwargs.pop('stream', sess.stream)
|
| timeout = kwargs.pop('timeout', None)
|
| kwargs['headers'] = {
|
| k.replace(
|
| '_',
|
| '-').upper(): v for k,
|
| v in kwargs.get(
|
| 'headers',
|
| {}).items()}
|
| prepped = requests.Request(**kwargs).prepare()
|
|
|
| if CLIENT_AUTHENTICATION and HTTP_APP_KEY and SECRET_KEY:
|
| timestamp = str(round(time() * 1000))
|
| nonce = str(uuid1())
|
| signature = b64encode(HMAC(SECRET_KEY.encode('ascii'), b'\n'.join([
|
| timestamp.encode('ascii'),
|
| nonce.encode('ascii'),
|
| HTTP_APP_KEY.encode('ascii'),
|
| prepped.path_url.encode('ascii'),
|
| prepped.body if kwargs.get('json') else b'',
|
| urlencode(
|
| sorted(
|
| kwargs['data'].items()),
|
| quote_via=quote,
|
| safe='-._~').encode('ascii')
|
| if kwargs.get('data') and isinstance(kwargs['data'], dict) else b'',
|
| ]), 'sha1').digest()).decode('ascii')
|
|
|
| prepped.headers.update({
|
| 'TIMESTAMP': timestamp,
|
| 'NONCE': nonce,
|
| 'APP-KEY': HTTP_APP_KEY,
|
| 'SIGNATURE': signature,
|
| })
|
|
|
| return sess.send(prepped, stream=stream, timeout=timeout)
|
|
|
|
|
| def get_exponential_backoff_interval(retries, full_jitter=False):
|
| """Calculate the exponential backoff wait time."""
|
|
|
| countdown = min(REQUEST_MAX_WAIT_SEC, REQUEST_WAIT_SEC * (2 ** retries))
|
|
|
|
|
| if full_jitter:
|
| countdown = random.randrange(countdown + 1)
|
|
|
| return max(0, countdown)
|
|
|
|
|
| def get_json_result(retcode=RetCode.SUCCESS, retmsg='success',
|
| data=None, job_id=None, meta=None):
|
| import re
|
| result_dict = {
|
| "retcode": retcode,
|
| "retmsg": retmsg,
|
|
|
| "data": data,
|
| "jobId": job_id,
|
| "meta": meta,
|
| }
|
|
|
| response = {}
|
| for key, value in result_dict.items():
|
| if value is None and key != "retcode":
|
| continue
|
| else:
|
| response[key] = value
|
| return jsonify(response)
|
|
|
|
|
| def get_data_error_result(retcode=RetCode.DATA_ERROR,
|
| retmsg='Sorry! Data missing!'):
|
| import re
|
| result_dict = {
|
| "retcode": retcode,
|
| "retmsg": re.sub(
|
| r"rag",
|
| "seceum",
|
| retmsg,
|
| flags=re.IGNORECASE)}
|
| response = {}
|
| for key, value in result_dict.items():
|
| if value is None and key != "retcode":
|
| continue
|
| else:
|
| response[key] = value
|
| return jsonify(response)
|
|
|
|
|
| def server_error_response(e):
|
| stat_logger.exception(e)
|
| try:
|
| if e.code == 401:
|
| return get_json_result(retcode=401, retmsg=repr(e))
|
| except BaseException:
|
| pass
|
| if len(e.args) > 1:
|
| return get_json_result(
|
| retcode=RetCode.EXCEPTION_ERROR, retmsg=repr(e.args[0]), data=e.args[1])
|
| if repr(e).find("index_not_found_exception") >=0:
|
| return get_json_result(retcode=RetCode.EXCEPTION_ERROR, retmsg="No chunk found, please upload file and parse it.")
|
|
|
| return get_json_result(retcode=RetCode.EXCEPTION_ERROR, retmsg=repr(e))
|
|
|
|
|
| def error_response(response_code, retmsg=None):
|
| if retmsg is None:
|
| retmsg = HTTP_STATUS_CODES.get(response_code, 'Unknown Error')
|
|
|
| return Response(json.dumps({
|
| 'retmsg': retmsg,
|
| 'retcode': response_code,
|
| }), status=response_code, mimetype='application/json')
|
|
|
|
|
| def validate_request(*args, **kwargs):
|
| def wrapper(func):
|
| @wraps(func)
|
| def decorated_function(*_args, **_kwargs):
|
| input_arguments = flask_request.json or flask_request.form.to_dict()
|
| no_arguments = []
|
| error_arguments = []
|
| for arg in args:
|
| if arg not in input_arguments:
|
| no_arguments.append(arg)
|
| for k, v in kwargs.items():
|
| config_value = input_arguments.get(k, None)
|
| if config_value is None:
|
| no_arguments.append(k)
|
| elif isinstance(v, (tuple, list)):
|
| if config_value not in v:
|
| error_arguments.append((k, set(v)))
|
| elif config_value != v:
|
| error_arguments.append((k, v))
|
| if no_arguments or error_arguments:
|
| error_string = ""
|
| if no_arguments:
|
| error_string += "required argument are missing: {}; ".format(
|
| ",".join(no_arguments))
|
| if error_arguments:
|
| error_string += "required argument values: {}".format(
|
| ",".join(["{}={}".format(a[0], a[1]) for a in error_arguments]))
|
| return get_json_result(
|
| retcode=RetCode.ARGUMENT_ERROR, retmsg=error_string)
|
| return func(*_args, **_kwargs)
|
| return decorated_function
|
| return wrapper
|
|
|
|
|
| def is_localhost(ip):
|
| return ip in {'127.0.0.1', '::1', '[::1]', 'localhost'}
|
|
|
|
|
| def send_file_in_mem(data, filename):
|
| if not isinstance(data, (str, bytes)):
|
| data = json_dumps(data)
|
| if isinstance(data, str):
|
| data = data.encode('utf-8')
|
|
|
| f = BytesIO()
|
| f.write(data)
|
| f.seek(0)
|
|
|
| return send_file(f, as_attachment=True, attachment_filename=filename)
|
|
|
|
|
| def get_json_result(retcode=RetCode.SUCCESS, retmsg='success', data=None):
|
| response = {"retcode": retcode, "retmsg": retmsg, "data": data}
|
| return jsonify(response)
|
|
|
|
|
| def cors_reponse(retcode=RetCode.SUCCESS,
|
| retmsg='success', data=None, auth=None):
|
| result_dict = {"retcode": retcode, "retmsg": retmsg, "data": data}
|
| response_dict = {}
|
| for key, value in result_dict.items():
|
| if value is None and key != "retcode":
|
| continue
|
| else:
|
| response_dict[key] = value
|
| response = make_response(jsonify(response_dict))
|
| if auth:
|
| response.headers["Authorization"] = auth
|
| response.headers["Access-Control-Allow-Origin"] = "*"
|
| response.headers["Access-Control-Allow-Method"] = "*"
|
| response.headers["Access-Control-Allow-Headers"] = "*"
|
| response.headers["Access-Control-Allow-Headers"] = "*"
|
| response.headers["Access-Control-Expose-Headers"] = "Authorization"
|
| return response
|
|
|