diff --git a/addon/flamenco/comms.py b/addon/flamenco/comms.py index 25582f4d..12d5161a 100644 --- a/addon/flamenco/comms.py +++ b/addon/flamenco/comms.py @@ -5,13 +5,18 @@ import logging from typing import TYPE_CHECKING +from urllib3.exceptions import HTTPError, MaxRetryError +import bpy + _flamenco_client = None _log = logging.getLogger(__name__) if TYPE_CHECKING: from flamenco.manager import ApiClient as _ApiClient + from .preferences import FlamencoPreferences as _FlamencoPreferences else: _ApiClient = object + _FlamencoPreferences = object def flamenco_api_client(manager_url: str) -> _ApiClient: @@ -43,3 +48,47 @@ def discard_flamenco_data(): _log.info("closing Flamenco client") _flamenco_client.close() _flamenco_client = None + + +def ping_manager(context: bpy.types.Context, api_client: _ApiClient, prefs: _FlamencoPreferences) -> tuple[str, str]: + """Ping the Manager, update preferences, and return a report as string. + + :returns: tuple (report, level). The report will be something like " + version found", or an error message. The level will be + 'ERROR', 'WARNING', or 'INFO', suitable for reporting via + `Operator.report()`. + """ + + # Do a late import, so that the API is only imported when actually used. + from flamenco.manager import ApiException + from flamenco.manager.apis import MetaApi + from flamenco.manager.models import FlamencoVersion, ManagerConfiguration + + context.window_manager.flamenco_status_ping = "..." + + meta_api = MetaApi(api_client) + try: + version: FlamencoVersion = meta_api.get_version() + config: ManagerConfiguration = meta_api.get_configuration() + except ApiException as ex: + report = "Manager cannot be reached: %s" % ex + level = "ERROR" + except MaxRetryError as ex: + # This is the common error, when for example the port number is + # incorrect and nothing is listening. + report = "Manager cannot be reached" + level = "WARNING" + except HTTPError as ex: + report = "Manager cannot be reached: %s" % ex + level = "ERROR" + else: + report = "%s version %s found" % (version.name, version.version) + level = "INFO" + + # Store whether this Manager supports the Shaman API. + prefs.is_shaman_enabled = config.shaman_enabled + prefs.job_storage = config.storage_location + + context.window_manager.flamenco_status_ping = report + + return report, level diff --git a/addon/flamenco/operators.py b/addon/flamenco/operators.py index 57d295eb..935e42db 100644 --- a/addon/flamenco/operators.py +++ b/addon/flamenco/operators.py @@ -5,7 +5,7 @@ import datetime import logging from pathlib import Path, PurePosixPath from typing import Optional, TYPE_CHECKING -from urllib3.exceptions import HTTPError, MaxRetryError +from urllib3.exceptions import MaxRetryError import bpy @@ -81,40 +81,14 @@ class FLAMENCO_OT_ping_manager(FlamencoOpMixin, bpy.types.Operator): bl_options = {"REGISTER"} # No UNDO. def execute(self, context: bpy.types.Context) -> set[str]: + from . import comms, preferences + api_client = self.get_api_client(context) + prefs = preferences.get(context) - from flamenco.manager import ApiException - from flamenco.manager.apis import MetaApi - from flamenco.manager.models import FlamencoVersion, ManagerConfiguration - - context.window_manager.flamenco_status_ping = "..." - - meta_api = MetaApi(api_client) - try: - version: FlamencoVersion = meta_api.get_version() - config: ManagerConfiguration = meta_api.get_configuration() - except ApiException as ex: - report = "Manager cannot be reached: %s" % ex - level = "ERROR" - except MaxRetryError as ex: - # This is the common error, when for example the port number is - # incorrect and nothing is listening. - report = "Manager cannot be reached" - level = "WARNING" - except HTTPError as ex: - report = "Manager cannot be reached: %s" % ex - level = "ERROR" - else: - report = "%s version %s found" % (version.name, version.version) - level = "INFO" - - # Store whether this Manager supports the Shaman API. - prefs = preferences.get(context) - prefs.is_shaman_enabled = config.shaman_enabled - prefs.job_storage = config.storage_location - + report, level = comms.ping_manager(context, api_client, prefs) self.report({level}, report) - context.window_manager.flamenco_status_ping = report + return {"FINISHED"} diff --git a/addon/flamenco/preferences.py b/addon/flamenco/preferences.py index 47f6159e..437a6a06 100644 --- a/addon/flamenco/preferences.py +++ b/addon/flamenco/preferences.py @@ -4,7 +4,7 @@ import bpy -def discard_flamenco_client(prefs, context): +def discard_flamenco_client(context): """Discard any cached Flamenco client after the Manager URL changes.""" from . import comms @@ -22,6 +22,18 @@ def _refresh_the_planet( region.tag_redraw() +def _manager_url_updated(prefs, context): + discard_flamenco_client(context) + + from . import comms + + api_client = comms.flamenco_api_client(prefs.manager_url) + + # Warning, be careful what of the context to access here. Accessing / + # changing too much can cause crashes, infinite loops, etc. + comms.ping_manager(context, api_client, prefs) + + class FlamencoPreferences(bpy.types.AddonPreferences): bl_idname = "flamenco" @@ -29,7 +41,7 @@ class FlamencoPreferences(bpy.types.AddonPreferences): name="Manager URL", description="Location of the Manager", default="http://localhost:8080/", - update=discard_flamenco_client, + update=_manager_url_updated, ) is_shaman_enabled: bpy.props.BoolProperty( # type: ignore @@ -68,16 +80,25 @@ class FlamencoPreferences(bpy.types.AddonPreferences): row = col.row(align=True) row.prop(self, "manager_url") - row.operator("flamenco.ping_manager", text="", icon="CHECKMARK") - if context.window_manager.flamenco_status_ping: - split = col.split(factor=0.4) + row.operator("flamenco.ping_manager", text="", icon="FILE_REFRESH") + + def text_row(parent, label): + split = parent.split(factor=0.4) split.label(text="") - split.label(text=context.window_manager.flamenco_status_ping) + split.label(text=label) + + if not self.job_storage: + text_row(col, "Press the refresh button before using Flamenco") + + if context.window_manager.flamenco_status_ping: + text_row(col, context.window_manager.flamenco_status_ping) + else: + aligned = col.column(align=True) + text_row(aligned, "Press the refresh button to check the connection") + text_row(aligned, "and update the job storage location") if self.is_shaman_enabled: - split = col.split(factor=0.4) - split.label(text="") - split.label(text="Shaman enabled") + text_row(col, "Shaman enabled") col.prop(self, "job_storage_for_gui", text="Job Storage")