diff --git a/single_ursim_control/main.py b/single_ursim_control/main.py index 28705b2..ce98c0e 100644 --- a/single_ursim_control/main.py +++ b/single_ursim_control/main.py @@ -2,7 +2,7 @@ import os import sys from config import Config -from plugins import SleepPlugin, SyncPlugin +from plugins import SleepPlugin, SyncPlugin, WaitPlugin from plugin_repository import PluginRepository from program_executor import ProgramExecutor from http_server import ControllerHTTPServer @@ -35,12 +35,15 @@ def main(): compiler_repo = PluginRepository() compiler_repo.register_plugin(SleepPlugin) compiler_repo.register_plugin(SyncPlugin) + compiler_repo.register_plugin(WaitPlugin) # Example code: compiler_repo.load_plugin("sleep") compiler_repo.load_plugin("sync") + compiler_repo.load_plugin("wait") program = [] program.append(compiler_repo.get_compiler("sleep").compile(secs=2)) + program.append(compiler_repo.get_compiler("wait").compile()) program.append(compiler_repo.get_compiler("sleep").compile(secs=3)) program.append(compiler_repo.get_compiler("sync").compile(nodes=2, name="test")) program.append(compiler_repo.get_compiler("sleep").compile(secs=10)) diff --git a/single_ursim_control/plugins/__init__.py b/single_ursim_control/plugins/__init__.py index 6a07a62..6b32910 100644 --- a/single_ursim_control/plugins/__init__.py +++ b/single_ursim_control/plugins/__init__.py @@ -1,3 +1,4 @@ from .abstract_plugin import AbstractCommand, AbstractCommandCompiler, AbstractPlugin from .sleep_plugin import SleepPlugin -from .sync_plugin import SyncPlugin \ No newline at end of file +from .sync_plugin import SyncPlugin +from .wait_plugin import WaitPlugin \ No newline at end of file diff --git a/single_ursim_control/plugins/wait_plugin.py b/single_ursim_control/plugins/wait_plugin.py new file mode 100644 index 0000000..ea57227 --- /dev/null +++ b/single_ursim_control/plugins/wait_plugin.py @@ -0,0 +1,68 @@ +import threading +from typing import Dict + +from .abstract_plugin import AbstractCommand, AbstractPlugin, AbstractCommandCompiler +import logging +from threading import Event + + +# +# I have to admit, the abort() solution is not the most robust thing I've ever designed +# But for this simple scenario, it's good enough +# + +class WaitCommand(AbstractCommand): + + def __init__(self, logger: logging.Logger, shared_event: threading.Event): + self._shared_event = shared_event + self._logger = logger + self._aborted = False + + def execute(self): + self._logger.debug(f"Waiting for user interaction...") + self._aborted = False # Have to reset, because of looping + self._shared_event.clear() + self._shared_event.wait() + + if self._aborted: + self._logger.warning("Waiting for interaction aborted externally!") + else: + self._logger.debug(f"User interaction received!") + + def abort(self): + self._aborted = True + self._shared_event.set() # <- force the event.wait to return + + def describe(self) -> dict: + return { + "command": "wait" + } + + +class WaitCompiler(AbstractCommandCompiler): + + def __init__(self, logger: logging.Logger, shared_event: threading.Event): + self._logger = logger + self._shared_event = shared_event + + def compile(self) -> AbstractCommand: + return WaitCommand(self._logger, self._shared_event) + + +class WaitPlugin(AbstractPlugin): + plugin_name = "wait" + + def __init__(self): + self._logger = logging.getLogger("plugin").getChild("wait") + self._shared_event = threading.Event() + + def load_compilers(self) -> Dict[str, AbstractCommandCompiler]: + return { + "wait": WaitCompiler(self._logger, self._shared_event) + } + + def cont(self): # <- magic + self._shared_event.set() + + def close(self): + pass