Issues 351 - Tartarus Integration
- Creating API to communicate with remote server - Updating Identity data - Adapting RemoteConfiguration load to new serverpull/420/head
parent
0ecb369397
commit
3280d57b18
|
@ -0,0 +1,57 @@
|
|||
import requests
|
||||
|
||||
from mycroft.configuration import ConfigurationManager
|
||||
from mycroft.identity import IdentityManager
|
||||
|
||||
|
||||
class Api(object):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
config = ConfigurationManager.get()
|
||||
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):
|
||||
method = params.get("method", "GET")
|
||||
headers = self.build_headers(params)
|
||||
body = self.build_body(params)
|
||||
url = self.build_url(params)
|
||||
return requests.request(method, url, headers=headers, data=body)
|
||||
|
||||
def build_headers(self, params):
|
||||
headers = params.get("headers", {})
|
||||
self.add_content_type(headers)
|
||||
self.add_authorization(headers)
|
||||
return headers
|
||||
|
||||
def add_content_type(self, headers):
|
||||
if not headers["Content-Type"]:
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
def add_authorization(self, headers):
|
||||
if not headers["Authorization"]:
|
||||
headers["Authorization"] = "Bearer " + self.identity.token
|
||||
|
||||
def build_body(self, params):
|
||||
body = params.get("body")
|
||||
if body and params["headers"]["Content-Type"] == "application/json":
|
||||
for k, v in body:
|
||||
if v == "":
|
||||
body[k] = None
|
||||
return body
|
||||
|
||||
def build_url(self, params):
|
||||
path = params.get("path", "")
|
||||
version = params.get("version", self.version)
|
||||
return self.url + "/" + version + "/" + self.path + path
|
||||
|
||||
|
||||
class DeviceApi(Api):
|
||||
def __init__(self):
|
||||
super(DeviceApi, self).__init__("device")
|
||||
|
||||
def find_setting(self):
|
||||
params = {"path": "/" + self.identity.device_id + "/setting"}
|
||||
return self.request(params)
|
|
@ -80,7 +80,7 @@ class CerberusGoogleProxy(object):
|
|||
timer.start()
|
||||
identity = IdentityManager().get()
|
||||
headers = {}
|
||||
if identity.token:
|
||||
if identity:
|
||||
headers['Authorization'] = 'Bearer %s:%s' % (
|
||||
identity.device_id, identity.token)
|
||||
|
||||
|
|
|
@ -16,13 +16,11 @@
|
|||
# along with Mycroft Core. If not, see <http://www.gnu.org/licenses/>.
|
||||
import collections
|
||||
|
||||
import requests
|
||||
from configobj import ConfigObj
|
||||
from genericpath import exists, isfile
|
||||
from os.path import join, dirname, expanduser
|
||||
|
||||
from mycroft.identity import IdentityManager
|
||||
from mycroft.util import str2bool
|
||||
from mycroft.api import DeviceApi
|
||||
from mycroft.util.log import getLogger
|
||||
|
||||
__author__ = 'seanfitz, jdorleans'
|
||||
|
@ -106,11 +104,11 @@ class RemoteConfiguration(object):
|
|||
config in the [core] config section
|
||||
"""
|
||||
__remote_keys = {
|
||||
"default_location": "location",
|
||||
"default_language": "lang",
|
||||
"timezone": "timezone"
|
||||
"unit": "unit"
|
||||
}
|
||||
|
||||
__api = DeviceApi()
|
||||
|
||||
@staticmethod
|
||||
def validate_config(config):
|
||||
if not (config and isinstance(config, dict)):
|
||||
|
@ -119,20 +117,14 @@ class RemoteConfiguration(object):
|
|||
|
||||
@staticmethod
|
||||
def load(config=None):
|
||||
api = RemoteConfiguration.__api
|
||||
RemoteConfiguration.validate_config(config)
|
||||
auto_update = config.get("server", {}).get("auto_update", False)
|
||||
|
||||
identity = IdentityManager().get()
|
||||
config_remote = config.get("remote_configuration", {})
|
||||
enabled = str2bool(config_remote.get("enabled", "False"))
|
||||
|
||||
if enabled and identity.token:
|
||||
url = config_remote.get("url")
|
||||
auth_header = "Bearer %s:%s" % (identity.device_id, identity.token)
|
||||
if auto_update:
|
||||
try:
|
||||
response = requests.get(url,
|
||||
headers={"Authorization": auth_header})
|
||||
user = response.json()
|
||||
RemoteConfiguration.__load_attributes(config, user)
|
||||
setting = api.find_setting().json()
|
||||
RemoteConfiguration.__load_attributes(config, setting)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to fetch remote configuration: %s" % repr(e))
|
||||
|
@ -142,18 +134,16 @@ class RemoteConfiguration(object):
|
|||
return config
|
||||
|
||||
@staticmethod
|
||||
def __load_attributes(config, user):
|
||||
def __load_attributes(config, setting):
|
||||
config_core = config["core"]
|
||||
|
||||
for att in user["attributes"]:
|
||||
att_name = att.get("attribute_name")
|
||||
name = RemoteConfiguration.__remote_keys.get(att_name)
|
||||
for k, v in setting:
|
||||
key = RemoteConfiguration.__remote_keys.get(k)
|
||||
|
||||
if name:
|
||||
config_core[name] = str(att.get("attribute_value"))
|
||||
logger.info(
|
||||
"Accepting remote configuration: core[%s] == %s" %
|
||||
(name, att["attribute_value"]))
|
||||
if config_core.__contains__(key):
|
||||
config_core[key] = str(v)
|
||||
logger.info("Setting remote configuration: core[%s] == %s" %
|
||||
(key, v))
|
||||
|
||||
|
||||
class ConfigurationManager(object):
|
||||
|
|
|
@ -7,6 +7,11 @@ date.format = "%A, %B %d, %Y"
|
|||
stop_threshold = 2 # in seconds
|
||||
third_party_skills_dir = "~/.mycroft/third_party_skills"
|
||||
|
||||
[server]
|
||||
url = "https://api.mycroft.ai"
|
||||
version = "v1"
|
||||
auto_update = True
|
||||
|
||||
[messagebus_service]
|
||||
host = "0.0.0.0"
|
||||
port = 8000
|
||||
|
@ -28,10 +33,6 @@ port = 443
|
|||
route = "/pairing"
|
||||
ssl = True
|
||||
|
||||
[remote_configuration]
|
||||
url = "https://cerberus.mycroft.ai/user"
|
||||
enabled = True
|
||||
|
||||
[speech_client]
|
||||
sample_rate = 16000
|
||||
channels = 1
|
||||
|
|
|
@ -16,47 +16,33 @@
|
|||
# along with Mycroft Core. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from uuid import uuid4
|
||||
import json
|
||||
|
||||
from mycroft.filesystem import FileSystemAccess
|
||||
|
||||
|
||||
class DeviceIdentity(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.device_id = kwargs.get('device_id')
|
||||
self.owner = kwargs.get('owner')
|
||||
self.token = kwargs.get('token')
|
||||
|
||||
@staticmethod
|
||||
def load(identity_file_handle):
|
||||
json_blob = json.load(identity_file_handle)
|
||||
return DeviceIdentity(**json_blob)
|
||||
|
||||
def save(self, identity_file_handle):
|
||||
json.dump(self.__dict__, identity_file_handle)
|
||||
|
||||
|
||||
class IdentityManager(object):
|
||||
FILE = 'identity.json'
|
||||
|
||||
def __init__(self):
|
||||
self.filesystem = FileSystemAccess('identity')
|
||||
self.file_system = FileSystemAccess('identity')
|
||||
self.identity = None
|
||||
self.initialize()
|
||||
self.load()
|
||||
|
||||
def initialize(self):
|
||||
if self.filesystem.exists('identity.json'):
|
||||
self.identity = DeviceIdentity.load(self.filesystem.open(
|
||||
'identity.json', 'r'))
|
||||
else:
|
||||
identity = DeviceIdentity(device_id=str(uuid4()))
|
||||
self.update(identity)
|
||||
def load(self):
|
||||
with self.file_system.open(self.FILE, 'r') as f:
|
||||
self.identity = DeviceIdentity(**json.load(f))
|
||||
|
||||
def update(self, identity):
|
||||
def save(self, identity):
|
||||
self.identity = identity
|
||||
with self.filesystem.open('identity.json', 'w') as f:
|
||||
self.identity.save(f)
|
||||
|
||||
def is_paired(self):
|
||||
return self.identity is not None and self.identity.owner is not None
|
||||
with self.file_system.open(self.FILE, 'w') as f:
|
||||
json.dump(self.identity, f)
|
||||
|
||||
def get(self):
|
||||
return self.identity
|
||||
|
|
|
@ -46,14 +46,11 @@ class DevicePairingClient(object):
|
|||
pairing_code if pairing_code else generate_pairing_code())
|
||||
|
||||
def on_registration(self, message):
|
||||
# TODO: actually accept the configuration message and store it in
|
||||
# identity
|
||||
payload = message.metadata
|
||||
identity = self.identity_manager.get()
|
||||
register_payload = message.metadata
|
||||
if register_payload.get("device_id") == identity.device_id:
|
||||
identity.token = register_payload.get('token')
|
||||
identity.owner = register_payload.get('user')
|
||||
self.identity_manager.update(identity)
|
||||
if identity and payload.get("device_id") == identity.device_id:
|
||||
identity.token = payload.get('token')
|
||||
self.identity_manager.save(identity)
|
||||
self.ws_client.close()
|
||||
self.paired = True
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class CerberusConfigSkill(MycroftSkill):
|
|||
|
||||
def handle_update_intent(self, message):
|
||||
identity = IdentityManager().get()
|
||||
if not identity.owner:
|
||||
if identity:
|
||||
self.speak_dialog("not.paired")
|
||||
else:
|
||||
ConfigurationManager.load_remote()
|
||||
|
|
|
@ -17,18 +17,17 @@
|
|||
|
||||
|
||||
from StringIO import StringIO
|
||||
from os.path import dirname, join
|
||||
|
||||
import re
|
||||
import requests
|
||||
import wolframalpha
|
||||
from os.path import dirname, join
|
||||
from six.moves import urllib
|
||||
|
||||
from mycroft.identity import IdentityManager
|
||||
from mycroft.skills.core import MycroftSkill
|
||||
from mycroft.util import CerberusAccessDenied
|
||||
from mycroft.util.log import getLogger
|
||||
from mycroft.messagebus.message import Message
|
||||
|
||||
__author__ = 'seanfitz'
|
||||
|
||||
|
@ -83,8 +82,12 @@ class CerberusWolframAlphaClient(object):
|
|||
"""
|
||||
Query Wolfram|Alpha with query using the v2.0 API
|
||||
"""
|
||||
response = {}
|
||||
identity = IdentityManager().get()
|
||||
bearer_token = 'Bearer %s:%s' % (identity.device_id, identity.token)
|
||||
|
||||
if identity:
|
||||
bearer_token = 'Bearer %s:%s' % \
|
||||
(identity.device_id, identity.token)
|
||||
query = urllib.parse.urlencode(dict(input=query))
|
||||
url = 'https://cerberus.mycroft.ai/wolframalpha/v2/query?' + query
|
||||
headers = {'Authorization': bearer_token}
|
||||
|
|
Loading…
Reference in New Issue