From 9bc081dad2e1c30e90ee5f81e77091defa1724ad Mon Sep 17 00:00:00 2001 From: Nuno Pereira Date: Fri, 5 Jan 2024 15:54:42 +0000 Subject: [PATCH] fix: move command interpreter setup to scene --- arena/arena_mqtt.py | 19 +------------------ arena/scene.py | 16 ++++++++++++++-- arena/utils/cmd_interpreter.py | 12 +++++++----- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/arena/arena_mqtt.py b/arena/arena_mqtt.py index d21a54f5..ec7ddc88 100644 --- a/arena/arena_mqtt.py +++ b/arena/arena_mqtt.py @@ -7,14 +7,12 @@ import ssl import sys from datetime import datetime -import threading import paho.mqtt.client as mqtt from .auth import ArenaAuth from .event_loop import * -from .utils import ArenaCmdInterpreter, ProgramStats - +from .utils import ProgramStats class ArenaMQTT(object): """ Wrapper around Paho MQTT client and EventLoop. @@ -158,9 +156,6 @@ def __init__( self.msg_queue = asyncio.Queue() - # setup event to let others wait on connection - self.connected_evt = threading.Event() - # connect to mqtt broker if "port" in kwargs: port = kwargs["port"] @@ -177,15 +172,6 @@ def __init__( print(f'MQTT connect error to {self.mqtt_host}, port={port}: Result Code={err}') self.mqttc.socket().setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2048) - # check if we want to start the command interpreter - enable_interp = os.environ.get("ENABLE_INTERPRETER", 'False').lower() in ('true', '1', 't') - if enable_interp: - self.cmd_interpreter = ArenaCmdInterpreter(self, - show_attrs=('config_data', 'scene', 'users', 'all_objects', 'stats'), - get_callables=('persisted_objs', 'persisted_scene_option', 'writable_scenes', 'user_list')) - self.cmd_interpreter.start_thread(self.connected_evt) - - def parse_cli(self): """ Reusable command-line options to give apps flexible options to avoid hard-coding locations. @@ -306,9 +292,6 @@ def on_connect(self, client, userdata, flags, rc): client.subscribe(self.subscribe_topic) client.message_callback_add(self.subscribe_topic, self.on_message) - # set event - self.connected_evt.set() - # reset msg rate time self.msg_rate_time_start = datetime.now() diff --git a/arena/scene.py b/arena/scene.py index 2fb7fbbe..e2eaccdd 100644 --- a/arena/scene.py +++ b/arena/scene.py @@ -5,12 +5,13 @@ import sys from datetime import datetime from inspect import signature +import threading from .arena_mqtt import ArenaMQTT from .attributes import * from .events import * from .objects import * -from .utils import Utils, ArenaTelemetry +from .utils import Utils, ArenaTelemetry, ArenaCmdInterpreter class Scene(ArenaMQTT): """ @@ -42,6 +43,14 @@ def __init__( # init telemetry self.telemetry = ArenaTelemetry() + + # setup event to let others wait on connection + self.connected_evt = threading.Event() + + # start the command interpreter (if enabled by env variable) + self.cmd_interpreter = ArenaCmdInterpreter(self, show_attrs=('config_data', 'scene', 'users', 'all_objects', 'stats'), + get_callables=('persisted_objs', 'persisted_scene_option', 'writable_scenes', 'user_list'), + start_cmd_event=self.connected_evt) if cli_args: self.args = self.parse_cli() @@ -109,8 +118,11 @@ def exit(self, arg=0): def on_connect(self, client, userdata, flags, rc): super().on_connect(client, userdata, flags, rc) if rc == 0: + # set event + self.connected_evt.set() + # create arena-py Objects from persist server - # no need to return anything here + # no need to return anything here self.get_persisted_objs() async def process_message(self): diff --git a/arena/utils/cmd_interpreter.py b/arena/utils/cmd_interpreter.py index bda63172..c8cb4206 100644 --- a/arena/utils/cmd_interpreter.py +++ b/arena/utils/cmd_interpreter.py @@ -14,20 +14,22 @@ def __serialize_obj(self, obj): return {k: v for k, v in vars(obj).items() if k.startswith("_") == False} # ignore private members raise TypeError("Type not serializable") - def __init__(self, scene, show_attrs=('config_data', 'scene', 'users', 'all_objects', 'msg_io'), get_callables=('persisted_objs', 'persisted_scene_option', 'writable_scenes', 'user_list')): + def __init__(self, scene, show_attrs=('config_data', 'scene', 'users', 'all_objects', 'msg_io'), get_callables=('persisted_objs', 'persisted_scene_option', 'writable_scenes', 'user_list'), start_cmd_event=None): + self.enable_interp = os.environ.get("ENABLE_INTERPRETER", 'False').lower() in ('true', '1', 't') + if not self.enable_interp: return super().__init__(completekey='tab') self._scene = scene self._show_attrs = show_attrs self._get_callables = get_callables + + # start interpreter thread + t = threading.Thread(name='interpreter_thread', target=self.__cmd_loop_thread, args=(start_cmd_event,)) + t.start() def __cmd_loop_thread(self, start_cmd_event): if start_cmd_event: start_cmd_event.wait(5) # try to start cmd last; wait on event with timeout self.cmdloop() - def start_thread(self, start_cmd_event=None): - t = threading.Thread(name='interpreter_thread', target=self.__cmd_loop_thread, args=(start_cmd_event,)) - t.start() - def do_show(self, arg): if arg not in self._show_attrs: self.help_show()