<commit_before># Copyright 2017 Mycroft AI Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from copy import copy

import json
import requests
from requests import HTTPError, RequestException
import os
import time

from mycroft.configuration import Configuration
from mycroft.configuration.config import DEFAULT_CONFIG, SYSTEM_CONFIG, \
    USER_CONFIG
from mycroft.identity import IdentityManager, identity_lock
from mycroft.version import VersionManager
from mycroft.util import get_arch, connected, LOG


_paired_cache = False


class BackendDown(RequestException):
    pass


class InternetDown(RequestException):
    pass


class Api:
    """ Generic class to wrap web APIs """
    params_to_etag = {}
    etag_to_response = {}

    def __init__(self, path):
        self.path = path

        # Load the config, skipping the REMOTE_CONFIG since we are
        # getting the info needed to get to it!
        config = Configuration.get([DEFAULT_CONFIG,
                                    SYSTEM_CONFIG,
                                    USER_CONFIG],
                                   cache=False)
        config_server = config.get("server")
        self.url = config_server.get("url")
        self.version = config_server.get("version")
        self.identity = IdentityManager.get()

    def request(self, params):
        self.check_token()
        self.build_path(params)
        self.old_params = copy(params)
        return self.send(params)

    def check_token(self):
        # If the identity hasn't been loaded, load it
        if not self.identity.has_refresh():
            self.identity = IdentityManager.load()
        # If refresh is needed perform a refresh
        if self.identity.refresh and self.identity.is_expired():
            self.identity = IdentityManager.load()
            # if no one else has updated the token refresh it
            if self.identity.is_expired():
                self.refresh_token()

    def refresh_token(self):
        LOG.debug('Refreshing token')
        if identity_lock.acquire(blocking=False):
            try:
                data = self.send({
                    "path": "auth/token",
                    "headers": {
                        "Authorization": "Bearer " + self.identity.refresh
                    }
                })
                IdentityManager.save(data, lock=False)
                LOG.debug('Saved credentials')
            except HTTPError as e:
                if e.response.status_code == 401:
                    LOG.error('Could not refresh token, invalid refresh code.')
                else:
                    raise

            finally:
                identity_lock.release()
        else:  # Someone is updating the identity wait for release
            with identity_lock:
                LOG.debug('Refresh is already in progress, waiting until done')
                time.sleep(1.2)
                os.sync()
                self.identity = IdentityManager.load(lock=False)
                LOG.debug('new credentials loaded')

    def send(self, params, no_refresh=False):
        """ Send request to mycroft backend.
        The method handles Etags and will return a cached response value
        if nothing has changed on the remote.
<commit_msg>Pass the device id as part of the refresh sequence (#2134)<commit_after># Copyright 2017 Mycroft AI Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from copy import copy

import json
import requests
from requests import HTTPError, RequestException
import os
import time

from mycroft.configuration import Configuration
from mycroft.configuration.config import DEFAULT_CONFIG, SYSTEM_CONFIG, \
    USER_CONFIG
from mycroft.identity import IdentityManager, identity_lock
from mycroft.version import VersionManager
from mycroft.util import get_arch, connected, LOG


_paired_cache = False


class BackendDown(RequestException):
    pass


class InternetDown(RequestException):
    pass


class Api:
    """ Generic class to wrap web APIs """
    params_to_etag = {}
    etag_to_response = {}

    def __init__(self, path):
        self.path = path

        # Load the config, skipping the REMOTE_CONFIG since we are
        # getting the info needed to get to it!
        config = Configuration.get([DEFAULT_CONFIG,
                                    SYSTEM_CONFIG,
                                    USER_CONFIG],
                                   cache=False)
        config_server = config.get("server")
        self.url = config_server.get("url")
        self.version = config_server.get("version")
        self.identity = IdentityManager.get()

    def request(self, params):
        self.check_token()
        self.build_path(params)
        self.old_params = copy(params)
        return self.send(params)

    def check_token(self):
        # If the identity hasn't been loaded, load it
        if not self.identity.has_refresh():
            self.identity = IdentityManager.load()
        # If refresh is needed perform a refresh
        if self.identity.refresh and self.identity.is_expired():
            self.identity = IdentityManager.load()
            # if no one else has updated the token refresh it
            if self.identity.is_expired():
                self.refresh_token()

    def refresh_token(self):
        LOG.debug('Refreshing token')
        if identity_lock.acquire(blocking=False):
            try:
                data = self.send({
                    "path": "auth/token",
                    "headers": {
                        "Authorization": "Bearer " + self.identity.refresh,
                        "Device": self.identity.uuid
                    }
                })
                IdentityManager.save(data, lock=False)
                LOG.debug('Saved credentials')
            except HTTPError as e:
                if e.response.status_code == 401:
                    LOG.error('Could not refresh token, invalid refresh code.')
                else:
                    raise

            finally:
                identity_lock.release()
        else:  # Someone is updating the identity wait for release
            with identity_lock:
                LOG.debug('Refresh is already in progress, waiting until done')
                time.sleep(1.2)
                os.sync()
                self.identity = IdentityManager.load(lock=False)
                LOG.debug('new credentials loaded')

    def send(self, params, no_refresh=False):
        """ Send request to mycroft backend.
        The method handles Etags and will return a cached response value
        if nothing has changed on the remote.

{'fraction_non_alphanumeric': 0.07498358502954695, 'fraction_numerical': 0.003939592908732764, 'mean_word_length': 2.1022403258655804, 'pattern_counts': {'":': 7, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7284621', 'n_tokens_mistral': 1941, 'n_tokens_neox': 1829, 'n_words': 650}