#521 - Skill auto reload

pull/541/head
Augusto Monteiro 2017-02-21 02:43:50 -03:00 committed by Steve Penrod
parent e47e38c92c
commit 1b0afe92de
1 changed files with 78 additions and 24 deletions

View File

@ -17,13 +17,17 @@
import json import json
import sys import sys
import time
from threading import Timer
import os
from os.path import expanduser, exists from os.path import expanduser, exists
from mycroft.configuration import ConfigurationManager from mycroft.configuration import ConfigurationManager
from mycroft.messagebus.client.ws import WebsocketClient from mycroft.messagebus.client.ws import WebsocketClient
from mycroft.skills.core import load_skills, THIRD_PARTY_SKILLS_DIR from mycroft.skills.core import load_skills, THIRD_PARTY_SKILLS_DIR, \
load_skill, create_skill_descriptor, MainModule
from mycroft.util.log import getLogger from mycroft.util.log import getLogger
logger = getLogger("Skills") logger = getLogger("Skills")
@ -31,26 +35,9 @@ logger = getLogger("Skills")
__author__ = 'seanfitz' __author__ = 'seanfitz'
ws = None ws = None
skills = [] loaded_skills = {}
last_modified_skill = 0
skills_directories = []
def load_skills_callback():
global ws
global skills
skills += load_skills(ws)
config = ConfigurationManager.get().get("skills")
try:
ini_third_party_skills_dir = expanduser(config.get("directory"))
except AttributeError as e:
logger.warning(e.message)
for loc in THIRD_PARTY_SKILLS_DIR:
if exists(loc):
skills += load_skills(ws, loc)
if ini_third_party_skills_dir and exists(ini_third_party_skills_dir):
skills += load_skills(ws, ini_third_party_skills_dir)
def connect(): def connect():
@ -58,6 +45,73 @@ def connect():
ws.run_forever() 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
try:
config = ConfigurationManager.get().get("skills")
ini_third_party_skills_dir = expanduser(config.get("directory"))
if ini_third_party_skills_dir and exists(ini_third_party_skills_dir):
skills_directories.append(ini_third_party_skills_dir)
except AttributeError as e:
logger.warning(e.message)
timer = Timer(0, load_skills)
timer.daemon = True
timer.start()
# last_modified_skill = max(skills.values())
def clear_skill_events(instance):
global ws
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]
def load_skills():
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:
if not loaded_skills.has_key(skill_folder):
loaded_skills[skill_folder] = {}
skill = loaded_skills[skill_folder]
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:
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)
load_skills()
def main(): def main():
global ws global ws
ws = WebsocketClient() ws = WebsocketClient()
@ -76,7 +130,7 @@ def main():
logger.debug(message) logger.debug(message)
ws.on('message', echo) ws.on('message', echo)
ws.once('open', load_skills_callback) ws.once('open', load_watch_skills)
ws.run_forever() ws.run_forever()
@ -84,7 +138,7 @@ if __name__ == "__main__":
try: try:
main() main()
except KeyboardInterrupt: except KeyboardInterrupt:
for skill in skills: for skill in loaded_skills:
skill.shutdown() skill.shutdown()
finally: finally:
sys.exit() sys.exit()