155 lines
4.5 KiB
Python
155 lines
4.5 KiB
Python
# 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.
|
|
#
|
|
"""Daemon launched at startup to handle skill activities.
|
|
|
|
In this repo, you will not find an entry called mycroft-skills in the bin
|
|
directory. The executable gets added to the bin directory when installed
|
|
(see setup.py)
|
|
"""
|
|
import time
|
|
from dataclasses import dataclass
|
|
|
|
from lingua_franca import load_languages
|
|
|
|
import mycroft.lock
|
|
from mycroft.configuration import Configuration
|
|
from mycroft.messagebus.message import Message
|
|
from mycroft.util import (
|
|
connected,
|
|
reset_sigint_handler,
|
|
start_message_bus_client,
|
|
wait_for_exit_signal
|
|
)
|
|
from mycroft.util.log import LOG
|
|
from mycroft.util.process_utils import ProcessStatus, StatusCallbackMap
|
|
from .api import SkillApi
|
|
from .core import FallbackSkill
|
|
from .event_scheduler import EventScheduler
|
|
from .intent_service import IntentService
|
|
from .skill_manager import SkillManager
|
|
|
|
|
|
def on_started():
|
|
LOG.info('Skills service is starting up.')
|
|
|
|
|
|
def on_alive():
|
|
LOG.info('Skills service is alive.')
|
|
|
|
|
|
def on_ready():
|
|
LOG.info('Skills service is ready.')
|
|
|
|
|
|
def on_error(e='Unknown'):
|
|
LOG.info('Skills service failed to launch ({})'.format(repr(e)))
|
|
|
|
|
|
def on_stopping():
|
|
LOG.info('Skills service is shutting down...')
|
|
|
|
|
|
def main(alive_hook=on_alive, started_hook=on_started, ready_hook=on_ready,
|
|
error_hook=on_error, stopping_hook=on_stopping, watchdog=None):
|
|
reset_sigint_handler()
|
|
# Create PID file, prevent multiple instances of this service
|
|
mycroft.lock.Lock('skills')
|
|
bus = start_message_bus_client("SKILLS")
|
|
callbacks = StatusCallbackMap(on_started=started_hook,
|
|
on_alive=alive_hook,
|
|
on_ready=ready_hook,
|
|
on_error=error_hook,
|
|
on_stopping=stopping_hook)
|
|
status = ProcessStatus('skills', bus, callbacks)
|
|
_set_initialize_started_status(bus, status)
|
|
_load_language()
|
|
_register_intent_services(bus)
|
|
event_scheduler = EventScheduler(bus)
|
|
SkillApi.connect_bus(bus)
|
|
|
|
# _wait_for_internet_connection()
|
|
padatious_training = _intent_training_status()
|
|
|
|
def handle_intents_trained(_):
|
|
padatious_training.complete = True
|
|
bus.once('mycroft.skills.trained', handle_intents_trained)
|
|
skill_manager = SkillManager(bus, watchdog)
|
|
skill_manager.load_on_startup()
|
|
|
|
while not all((skill_manager.is_all_loaded(), padatious_training.complete)):
|
|
time.sleep(0.1)
|
|
_set_initialize_ended_status(bus, status)
|
|
skill_manager.start()
|
|
|
|
wait_for_exit_signal()
|
|
shutdown(skill_manager, event_scheduler, status)
|
|
|
|
|
|
def _set_initialize_started_status(bus, status):
|
|
bus.emit(Message("skills.initialize.started"))
|
|
status.set_started()
|
|
|
|
|
|
def _load_language():
|
|
config = Configuration.get()
|
|
lang_code = config.get("lang", "en-us")
|
|
load_languages([lang_code, "en-us"])
|
|
|
|
|
|
def _set_initialize_ended_status(bus, status):
|
|
bus.emit(Message("skills.initialize.ended"))
|
|
status.set_ready()
|
|
|
|
|
|
def _register_intent_services(bus):
|
|
"""Start up the all intent services and connect them as needed.
|
|
|
|
Args:
|
|
bus: messagebus client to register the services on
|
|
"""
|
|
service = IntentService(bus)
|
|
# Register handler to trigger fallback system
|
|
bus.on(
|
|
'mycroft.skills.fallback',
|
|
FallbackSkill.make_intent_failure_handler(bus)
|
|
)
|
|
return service
|
|
|
|
|
|
@dataclass
|
|
class _intent_training_status:
|
|
complete: bool = False
|
|
|
|
|
|
def _wait_for_internet_connection():
|
|
while not connected():
|
|
time.sleep(1)
|
|
|
|
|
|
def shutdown(skill_manager, event_scheduler, status):
|
|
LOG.info('Shutting down Skills service')
|
|
status.set_stopping()
|
|
if event_scheduler is not None:
|
|
event_scheduler.shutdown()
|
|
# Terminate all running threads that update skills
|
|
if skill_manager is not None:
|
|
skill_manager.stop()
|
|
skill_manager.join()
|
|
LOG.info('Skills service shutdown complete!')
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|