<commit_before>"""
HTTP API for bridge, aims to be restful.
Don't blame me for globals, blame the library.
"""

from bridge.services import BridgeService, HTTP_API, MODEL
from external_libs.bottle import run, Bottle, request, response, HTTPError
from external_libs import mimeparse, jsonpatch
import logging
import json
import time
import uuid

JSON_MIME = 'application/json'
JSON_PATCH_MIME = 'application/json-patch+patch'

def accept_only_json(func):
    """
    Decorator for a function that checks if the current request.content_type is an acceptable for
    the HTTP method.

    :param func: Function to decorate.
    :type func: func

    :return: The decorated function.
    :rtype: func
    """
    acceptable = JSON_MIME
    acceptable_patch = JSON_PATCH_MIME

    def mime_okay(mimetype, acceptable=acceptable):
        """
        Returns whether the mimetype is within the acceptable one.

        :param mimetype: MIME to check
        :parma mimetype: str

        :param acceptable: Valid MIME.
        :type acceptable: str

        :rtype: bool
        """
        accept = mimeparse.best_match([acceptable], mimetype)
        return accept == acceptable

    def error_non_json(*args, **kwargs):
        """
        Inner function that raises error if mimetype not acceptable.
        """
        if request.method == 'GET':
            if not mime_okay(request.get_header('Accept', acceptable)):
                raise HTTPError(406, "Please accept {0}".format(acceptable))

        elif request.method == 'POST':
            if not mime_okay(request.content_type):
                raise HTTPError(415, "Only accepts {0}.".format(acceptable))

        elif request.method == 'PATCH':
            if not mime_okay(request.content_type, acceptable_patch):
                raise HTTPError(415, "Only accepts {0}.".format(acceptable_patch))

        return func(*args, **kwargs)

    return error_non_json

class HTTPAPIService(BridgeService):
    """
    Service to provide a http api to bridge.

    :param hub_con: Connectionto BridgeHub
    :type hub_con: Pipe

    :param addr:
    :type addr:

    :param port:
    :type port;

    :param debug:
    :type debug: bool
    """

    def __init__(self, hub_con, addr='0.0.0.0', port='8080', debug=True):
        super().__init__(HTTP_API, hub_con)

        self.addr = addr
        self.port = port
        self.bottle = Bottle(catchall=False, autojson=False)
        self.json = json.JSONEncoder(sort_keys=True, indent=4)

        self.bottle.get('/', callback=self.bridge_information())
        self.bottle.post('/', callback=self.bridge_save())
        self.bottle.get('/services', callback=self.services())
        self.bottle.get('/services/<service>', callback=self.service_info())
        self.bottle.get('/assets', callback=self.assets())

        self.bottle.get('/assets/<asset>', callback=self.get_asset_by_uuid())
        self.bottle.route('/assets/<asset>', method='PATCH', callback=self.change_asset_by_uuid())
        self.bottle.delete('/assets/<asset>', callback=self.delete_asset_by_uuid())

        self.bottle.post('/assets/<asset>/<action>', callback=self.post_action())
        self.bottle.get('/assets/<asset>/<action>', callback=self.get_asset_action())
        self.bottle.post('/assets', callback=self.create_asset())


    def run(self):
        while True:
            try:
                run(app=self.bottle, host=self.addr, port=self.port, debug=True)
            except Exception:
                logging.exception("Net service errored out somehow.  Retrying in 5 seconds.")
                time.sleep(5)

    def bridge_information(self):
        """
        Return a function listing api urls.
        """
        @accept_only_json
        def inner_bridge_information():
            """
            Return api urls and model information.
            """
            base = request.url
            info = self.remote_block_service_method(MODEL, 'get_info')

            info['services_url'] = base + 'services/{service}'
            info['assets_url'] = base + 'assets/{asset uuid}'

            return self._encode(info)

        return inner_bridge_information

    def bridge_save(self):
        """
        Save the model information.
        """
        @accept_only_json<commit_msg>allow the http service to cleanly exit<commit_after>"""
HTTP API for bridge, aims to be restful.
Don't blame me for globals, blame the library.
"""

from bridge.services import BridgeService, HTTP_API, MODEL
from external_libs.bottle import run, Bottle, request, response, HTTPError
from external_libs import mimeparse, jsonpatch
import logging
import json
import time
import uuid

JSON_MIME = 'application/json'
JSON_PATCH_MIME = 'application/json-patch+patch'

def accept_only_json(func):
    """
    Decorator for a function that checks if the current request.content_type is an acceptable for
    the HTTP method.

    :param func: Function to decorate.
    :type func: func

    :return: The decorated function.
    :rtype: func
    """
    acceptable = JSON_MIME
    acceptable_patch = JSON_PATCH_MIME

    def mime_okay(mimetype, acceptable=acceptable):
        """
        Returns whether the mimetype is within the acceptable one.

        :param mimetype: MIME to check
        :parma mimetype: str

        :param acceptable: Valid MIME.
        :type acceptable: str

        :rtype: bool
        """
        accept = mimeparse.best_match([acceptable], mimetype)
        return accept == acceptable

    def error_non_json(*args, **kwargs):
        """
        Inner function that raises error if mimetype not acceptable.
        """
        if request.method == 'GET':
            if not mime_okay(request.get_header('Accept', acceptable)):
                raise HTTPError(406, "Please accept {0}".format(acceptable))

        elif request.method == 'POST':
            if not mime_okay(request.content_type):
                raise HTTPError(415, "Only accepts {0}.".format(acceptable))

        elif request.method == 'PATCH':
            if not mime_okay(request.content_type, acceptable_patch):
                raise HTTPError(415, "Only accepts {0}.".format(acceptable_patch))

        return func(*args, **kwargs)

    return error_non_json

class HTTPAPIService(BridgeService):
    """
    Service to provide a http api to bridge.

    :param hub_con: Connectionto BridgeHub
    :type hub_con: Pipe

    :param addr:
    :type addr:

    :param port:
    :type port;

    :param debug:
    :type debug: bool
    """

    def __init__(self, hub_con, addr='0.0.0.0', port='8080', debug=True):
        super().__init__(HTTP_API, hub_con)

        self.addr = addr
        self.port = port
        self.bottle = Bottle(catchall=False, autojson=False)
        self.json = json.JSONEncoder(sort_keys=True, indent=4)

        self.bottle.get('/', callback=self.bridge_information())
        self.bottle.post('/', callback=self.bridge_save())
        self.bottle.get('/services', callback=self.services())
        self.bottle.get('/services/<service>', callback=self.service_info())
        self.bottle.get('/assets', callback=self.assets())

        self.bottle.get('/assets/<asset>', callback=self.get_asset_by_uuid())
        self.bottle.route('/assets/<asset>', method='PATCH', callback=self.change_asset_by_uuid())
        self.bottle.delete('/assets/<asset>', callback=self.delete_asset_by_uuid())

        self.bottle.post('/assets/<asset>/<action>', callback=self.post_action())
        self.bottle.get('/assets/<asset>/<action>', callback=self.get_asset_action())
        self.bottle.post('/assets', callback=self.create_asset())


    def run(self):
        failing = True
        while failing:
            try:
                run(app=self.bottle, host=self.addr, port=self.port, debug=True)
                failing = False #run exited for a reasonable reason

            except Exception:
                logging.exception("Net service errored out somehow.  Retrying in 5 seconds.")
                time.sleep(5)

    def bridge_information(self):
        """
        Return a function listing api urls.
        """
        @accept_only_json
        def inner_bridge_information():
            """
            Return api urls and model information.
            """
            base = request.url
            info = self.remote_block_service_method(MODEL, 'get_info')

            info['services_url'] = base + 'services/{service}'
            info['assets_url'] = base + 'assets/{asset uuid}'

            return self._encode(info)

        return inner_bridge_information

    def bridge_save(self):
        """
        Save the model information.
        """
        @accept_only_json
{'fraction_non_alphanumeric': 0.11480119512755689, 'fraction_numerical': 0.005286141116984601, 'mean_word_length': 2.5962809917355374, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3379996', 'n_tokens_mistral': 2588, 'n_tokens_neox': 2496, 'n_words': 623}