Skip to content

Commit

Permalink
fix!:remove_deprecated_ready_msg
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed Oct 15, 2024
1 parent 4e609c8 commit 6d9ff11
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 179 deletions.
181 changes: 9 additions & 172 deletions ovos_core/skill_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import os
from os.path import basename
from threading import Thread, Event, Lock
from time import sleep, monotonic

from ovos_backend_client.pairing import is_paired
from time import monotonic

from ovos_bus_client.apis.enclosure import EnclosureAPI
from ovos_bus_client.client import MessageBusClient
from ovos_bus_client.message import Message
Expand Down Expand Up @@ -197,7 +197,6 @@ def _define_message_bus_events(self):
self.bus.on('skillmanager.deactivate', self.deactivate_skill)
self.bus.on('skillmanager.keep', self.deactivate_except)
self.bus.on('skillmanager.activate', self.activate_skill)
self.bus.once('mycroft.skills.initialized', self.handle_check_device_readiness)

# Load skills waiting for connectivity
self.bus.on("mycroft.network.connected", self.handle_network_connected)
Expand All @@ -207,111 +206,6 @@ def _define_message_bus_events(self):
self.bus.on("mycroft.internet.disconnected", self.handle_internet_disconnected)
self.bus.on("mycroft.gui.unavailable", self.handle_gui_disconnected)

def is_device_ready(self):
"""Check if the device is ready by waiting for various services to start.
Returns:
bool: True if the device is ready, False otherwise.
Raises:
TimeoutError: If the device is not ready within a specified timeout.
"""
is_ready = False
# Different setups will have different needs
# eg, a server does not care about audio
# pairing -> device is paired
# internet -> device is connected to the internet - NOT IMPLEMENTED
# skills -> skills reported ready
# speech -> stt reported ready
# audio -> audio playback reported ready
# gui -> gui websocket reported ready - NOT IMPLEMENTED
# enclosure -> enclosure/HAL reported ready - NOT IMPLEMENTED
services = {k: False for k in
self.config.get("ready_settings", ["skills"])}
start = monotonic()
while not is_ready:
is_ready = self.check_services_ready(services)
if is_ready:
break
elif monotonic() - start >= 60:
raise TimeoutError(
f'Timeout waiting for services start. services={services}')
else:
sleep(3)
return is_ready

def handle_check_device_readiness(self, message):
"""Handle the check device readiness event."""
ready = False
while not ready:
try:
ready = self.is_device_ready()
except TimeoutError:
if is_paired():
LOG.warning("OVOS should already have reported ready!")
sleep(5)

LOG.info("Mycroft is all loaded and ready to roll!")
self.bus.emit(message.reply('mycroft.ready'))

def check_services_ready(self, services):
"""Report if all specified services are ready.
Args:
services (iterable): Service names to check.
Returns:
bool: True if all specified services are ready, False otherwise.
"""
backend_type = self.config.get("server", {}).get("backend_type", "offline")
for ser, rdy in services.items():
if rdy:
# already reported ready
continue
if ser in ["pairing", "setup"]:

def setup_finish_interrupt(message):
nonlocal services
services[ser] = True

# if setup finishes naturally be ready early
self.bus.once("ovos.setup.finished", setup_finish_interrupt)

# pairing service (setup skill) needs to be available
# in offline mode (default) is_paired always returns True
# but setup skill may enable backend
# wait for backend selection event
response = self.bus.wait_for_response(
Message('ovos.setup.state.get',
context={"source": "skills",
"destination": "ovos-setup"}),
'ovos.setup.state')
if response:
state = response.data['state']
LOG.debug(f"Setup state: {state}")
if state == "finished":
services[ser] = True
elif not services[ser] and backend_type == "selene":
# older verson / alternate setup skill installed
services[ser] = is_paired(ignore_errors=True)
elif ser in ["gui", "enclosure"]:
# not implemented
services[ser] = True
continue
elif ser in ["skills"]:
services[ser] = self.status.check_ready()
continue
elif ser in ["network_skills"]:
services[ser] = self._network_loaded.is_set()
continue
elif ser in ["internet_skills"]:
services[ser] = self._internet_loaded.is_set()
continue
response = self.bus.wait_for_response(
Message(f'mycroft.{ser}.is_ready',
context={"source": "skills", "destination": ser}))
if response and response.data['status']:
services[ser] = True
return all([services[ser] for ser in services])

@property
def skills_config(self):
"""Get the skills service configuration.
Expand Down Expand Up @@ -469,86 +363,29 @@ def _load_plugin_skill(self, skill_id, skill_plugin):

return skill_loader if load_status else None

def load_priority(self):
"""DEPRECATED: Load priority skills based on the specified order in the configuration."""
skill_ids = {os.path.basename(skill_path): skill_path
for skill_path in self._get_skill_directories()}
priority_skills = self.skills_config.get("priority_skills") or []
if priority_skills:
update_code = """priority skills have been deprecated and support will be removed in a future release
Update skills with the following:
from ovos_utils.process_utils import RuntimeRequirements
from ovos_utils import classproperty
class MyPrioritySkill(OVOSSkill):
@classproperty
def network_requirements(self):
return RuntimeRequirements(internet_before_load=False,
network_before_load=False,
requires_internet=False,
requires_network=False)
"""
LOG.warning(update_code)
for skill_id in priority_skills:
LOG.info(f"Please refactor {skill_id} to specify offline network requirements")
skill_path = skill_ids.get(skill_id)
if skill_path is not None:
self._load_skill(skill_path)
else:
LOG.error(f'Priority skill {skill_id} can\'t be found')

def run(self):
"""Run the skill manager thread."""
self.load_priority()

self.status.set_alive()

self._load_on_startup()

if self.skills_config.get("wait_for_internet", False):
LOG.warning("`wait_for_internet` is a deprecated option, update to "
"specify `network_skills` or `internet_skills` in "
"`ready_settings`")
# NOTE - self._connected_event will never be set
# if PHAL plugin is not running to emit the connected events
while not self._connected_event.is_set():
# Ensure we don't block here forever if the plugin is not installed
self._sync_skill_loading_state()
sleep(1)
LOG.debug("Internet Connected")
else:
# trigger a sync so we dont need to wait for the plugin to volunteer info
self._sync_skill_loading_state()
# trigger a sync so we dont need to wait for the plugin to volunteer info
self._sync_skill_loading_state()

if "network_skills" in self.config.get("ready_settings"):
self._network_event.wait() # Wait for user to connect to network
if self._network_loaded.wait(self._network_skill_timeout):
LOG.debug("Network skills loaded")
else:
LOG.error("Gave up waiting for network skills to load")
if "internet_skills" in self.config.get("ready_settings"):
self._connected_event.wait() # Wait for user to connect to network
if self._internet_loaded.wait(self._network_skill_timeout):
LOG.debug("Internet skills loaded")
else:
LOG.error("Gave up waiting for internet skills to load")
if not all((self._network_loaded.is_set(),
self._internet_loaded.is_set())):
self.bus.emit(Message(
'mycroft.skills.error',
{'internet_loaded': self._internet_loaded.is_set(),
'network_loaded': self._network_loaded.is_set()}))

self.bus.emit(Message('mycroft.skills.initialized'))

self.status.set_ready()

if self._gui_event.is_set() and self._connected_event.is_set():
LOG.info("Skills all loaded!")
elif not self._connected_event.is_set():
LOG.info("Offline Skills loaded, waiting for Internet to load more!")
elif not self._gui_event.is_set():
LOG.info("Skills loaded, waiting for GUI to load more!")
self.bus.emit(Message('mycroft.ready'))

LOG.info("ovos-core is ready! additional skills can now be loaded")

# Scan the file folder that contains Skills. If a Skill is updated,
# unload the existing version from memory and reload from the disk.
Expand All @@ -564,7 +401,7 @@ def run(self):

def _load_on_network(self):
"""Load skills that require a network connection."""
if self._detected_installed_skills: # ensure we have skills is installed
if self._detected_installed_skills: # ensure we have skills is installed
LOG.info('Loading skills that require network...')
self._load_new_skills(network=True, internet=False)
self._network_loaded.set()
Expand Down
6 changes: 0 additions & 6 deletions test/unittests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ def test_handle_settings_file_change(self, mock_log):
self.bus.emit.assert_called_once_with(Message("ovos.skills.settings_changed", {"skill_id": "skills"}))
mock_log.info.assert_called_once_with(f"skill settings.json change detected for skills")

@patch('ovos_core.skill_manager.is_paired', side_effect=[False, True])
def test_handle_check_device_readiness(self, mock_is_paired):
self.skill_manager.is_device_ready = MagicMock(return_value=True)
self.skill_manager.handle_check_device_readiness(Message(""))
self.bus.emit.assert_called_once_with(Message('mycroft.ready'))

@patch('ovos_core.skill_manager.find_skill_plugins', return_value={'mock_plugin': 'path/to/mock_plugin'})
def test_load_plugin_skills(self, mock_find_skill_plugins):
self.skill_manager._load_plugin_skill = MagicMock(return_value=True)
Expand Down
2 changes: 1 addition & 1 deletion test/unittests/test_skill_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def test_instantiate(self):
'skillmanager.deactivate',
'skillmanager.keep',
'skillmanager.activate',
'mycroft.skills.initialized',
#'mycroft.skills.initialized',
'mycroft.network.connected',
'mycroft.internet.connected',
'mycroft.gui.available',
Expand Down

0 comments on commit 6d9ff11

Please sign in to comment.