2016-05-26 16:16:13 +00:00
|
|
|
# Copyright 2016 Mycroft AI, Inc.
|
|
|
|
#
|
|
|
|
# This file is part of Mycroft Core.
|
|
|
|
#
|
|
|
|
# Mycroft Core is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# Mycroft Core is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with Mycroft Core. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
import json
|
2017-01-28 00:36:19 +00:00
|
|
|
import sys
|
2017-02-21 05:43:50 +00:00
|
|
|
import time
|
|
|
|
from threading import Timer
|
|
|
|
|
|
|
|
import os
|
2016-07-18 20:45:11 +00:00
|
|
|
from os.path import expanduser, exists
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2016-06-17 18:47:25 +00:00
|
|
|
from mycroft.configuration import ConfigurationManager
|
2016-05-20 14:16:01 +00:00
|
|
|
from mycroft.messagebus.client.ws import WebsocketClient
|
2017-02-21 05:43:50 +00:00
|
|
|
from mycroft.skills.core import load_skills, THIRD_PARTY_SKILLS_DIR, \
|
|
|
|
load_skill, create_skill_descriptor, MainModule
|
2016-05-20 14:16:01 +00:00
|
|
|
from mycroft.util.log import getLogger
|
2016-09-17 02:08:53 +00:00
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
logger = getLogger("Skills")
|
|
|
|
|
|
|
|
__author__ = 'seanfitz'
|
|
|
|
|
2016-12-17 19:53:22 +00:00
|
|
|
ws = None
|
2017-02-21 05:43:50 +00:00
|
|
|
loaded_skills = {}
|
|
|
|
last_modified_skill = 0
|
|
|
|
skills_directories = []
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
|
2017-02-21 05:43:50 +00:00
|
|
|
def connect():
|
2016-12-17 19:53:22 +00:00
|
|
|
global ws
|
2017-02-21 05:43:50 +00:00
|
|
|
ws.run_forever()
|
|
|
|
|
|
|
|
|
|
|
|
def load_watch_skills():
|
|
|
|
global ws, loaded_skills, last_modified_skill, skills_directories
|
|
|
|
|
|
|
|
skills_directories = [os.path.dirname(os.path.abspath(__file__))]
|
|
|
|
skills_directories = skills_directories + THIRD_PARTY_SKILLS_DIR
|
2016-06-17 18:50:00 +00:00
|
|
|
|
2016-06-17 18:47:25 +00:00
|
|
|
try:
|
2017-02-21 05:43:50 +00:00
|
|
|
config = ConfigurationManager.get().get("skills")
|
2016-11-25 01:37:11 +00:00
|
|
|
ini_third_party_skills_dir = expanduser(config.get("directory"))
|
2017-02-21 05:43:50 +00:00
|
|
|
if ini_third_party_skills_dir and exists(ini_third_party_skills_dir):
|
|
|
|
skills_directories.append(ini_third_party_skills_dir)
|
2016-06-17 18:47:25 +00:00
|
|
|
except AttributeError as e:
|
|
|
|
logger.warning(e.message)
|
|
|
|
|
2017-02-21 22:13:14 +00:00
|
|
|
timer = Timer(0, watch_skills)
|
2017-02-21 05:43:50 +00:00
|
|
|
timer.daemon = True
|
|
|
|
timer.start()
|
2016-12-20 21:19:22 +00:00
|
|
|
|
2016-05-20 14:16:01 +00:00
|
|
|
|
2017-02-21 05:43:50 +00:00
|
|
|
def clear_skill_events(instance):
|
2016-12-17 19:53:22 +00:00
|
|
|
global ws
|
2017-02-21 05:43:50 +00:00
|
|
|
events = ws.emitter._events
|
|
|
|
instance_events = []
|
|
|
|
for event in events:
|
|
|
|
e = ws.emitter._events[event]
|
|
|
|
if len(e) > 0 and e[0].func_closure and isinstance(
|
|
|
|
e[0].func_closure[1].cell_contents, instance.__class__):
|
|
|
|
instance_events.append(event)
|
|
|
|
|
|
|
|
for event in instance_events:
|
|
|
|
del events[event]
|
|
|
|
|
|
|
|
|
2017-02-21 22:13:14 +00:00
|
|
|
def watch_skills():
|
2017-02-21 05:43:50 +00:00
|
|
|
global ws, loaded_skills, last_modified_skill, skills_directories
|
|
|
|
for dir in skills_directories:
|
|
|
|
if exists(dir):
|
|
|
|
list = filter(lambda x: os.path.isdir(os.path.join(dir, x)),
|
|
|
|
os.listdir(dir))
|
|
|
|
for skill_folder in list:
|
2017-02-21 22:13:14 +00:00
|
|
|
if not skill_folder in loaded_skills:
|
2017-02-21 05:43:50 +00:00
|
|
|
loaded_skills[skill_folder] = {}
|
2017-02-21 22:13:14 +00:00
|
|
|
skill = loaded_skills.get(skill_folder)
|
2017-02-21 05:43:50 +00:00
|
|
|
skill["path"] = os.path.join(dir, skill_folder)
|
|
|
|
if not MainModule + ".py" in os.listdir(skill["path"]):
|
|
|
|
continue
|
|
|
|
skill["last_modified"] = max(
|
|
|
|
os.path.getmtime(root) for root, _, _ in
|
|
|
|
os.walk(skill["path"]))
|
|
|
|
if skill.get("instance") and skill.get("last_modified",
|
|
|
|
0) <= last_modified_skill:
|
|
|
|
continue
|
|
|
|
elif skill.get("instance") and skill.get("last_modified",
|
|
|
|
0) > last_modified_skill:
|
2017-02-21 22:13:14 +00:00
|
|
|
logger.debug("Reloading Skill: " + skill_folder)
|
2017-02-21 05:43:50 +00:00
|
|
|
skill["instance"].shutdown()
|
|
|
|
clear_skill_events(skill["instance"])
|
|
|
|
del skill["instance"]
|
|
|
|
skill["instance"] = load_skill(
|
|
|
|
create_skill_descriptor(skill["path"]), ws)
|
|
|
|
last_modified_skill = max(
|
|
|
|
map(lambda x: x.get("last_modified"), loaded_skills.values()))
|
|
|
|
time.sleep(2)
|
2017-02-21 22:13:14 +00:00
|
|
|
watch_skills()
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2016-12-17 19:53:22 +00:00
|
|
|
global ws
|
|
|
|
ws = WebsocketClient()
|
|
|
|
ConfigurationManager.init(ws)
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
def echo(message):
|
|
|
|
try:
|
|
|
|
_message = json.loads(message)
|
|
|
|
|
2016-09-04 00:59:39 +00:00
|
|
|
if _message.get("type") == "registration":
|
2016-05-20 14:16:01 +00:00
|
|
|
# do not log tokens from registration messages
|
2016-09-04 01:24:18 +00:00
|
|
|
_message["data"]["token"] = None
|
2016-05-20 14:16:01 +00:00
|
|
|
message = json.dumps(_message)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
logger.debug(message)
|
|
|
|
|
2016-12-17 19:53:22 +00:00
|
|
|
ws.on('message', echo)
|
2017-02-21 05:43:50 +00:00
|
|
|
ws.once('open', load_watch_skills)
|
2016-12-17 19:53:22 +00:00
|
|
|
ws.run_forever()
|
2016-05-20 14:16:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2017-01-27 03:00:37 +00:00
|
|
|
try:
|
|
|
|
main()
|
|
|
|
except KeyboardInterrupt:
|
2017-02-21 05:43:50 +00:00
|
|
|
for skill in loaded_skills:
|
2017-01-27 18:32:20 +00:00
|
|
|
skill.shutdown()
|
2017-01-28 00:36:19 +00:00
|
|
|
finally:
|
|
|
|
sys.exit()
|