From 10665656a8efd046ba8fb01c6c8ae6b21f46fca3 Mon Sep 17 00:00:00 2001 From: Nuno Pereira Date: Tue, 25 Jul 2023 21:23:22 +0100 Subject: [PATCH] fix: move interpreter to a thread --- arena/arena_mqtt.py | 21 ++++++++++++++------- arena/utils/cmd_interpreter.py | 14 ++++++++------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/arena/arena_mqtt.py b/arena/arena_mqtt.py index 0f15328c..00e2770c 100644 --- a/arena/arena_mqtt.py +++ b/arena/arena_mqtt.py @@ -7,6 +7,7 @@ import ssl import sys from datetime import datetime +import threading import paho.mqtt.client as mqtt @@ -149,13 +150,8 @@ def __init__( self.msg_queue = asyncio.Queue() - # check if we want to start the command interpreter - enable_interp = os.getenv("ENABLE_INTERPRETER", 'False').lower() in ('true', '1', 't') - if enable_interp: - self.cmd_interpreter = ArenaCmdInterpreter(self, - show_attrs=('config_data', 'scene', 'users', 'auth', 'all_objects', 'msg_io'), - get_callables=('persisted_objs', 'persisted_scene_option', 'writable_scenes', 'user_list')) - self.run_async(self.cmd_interpreter.cmd_loop_task) + # setup event to let others wait on connection + self.connected_evt = threading.Event() # connect to mqtt broker if "port" in kwargs: @@ -173,6 +169,14 @@ 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.getenv("ENABLE_INTERPRETER", 'False').lower() in ('true', '1', 't') + if enable_interp: + self.cmd_interpreter = ArenaCmdInterpreter(self, + show_attrs=('config_data', 'scene', 'users', 'auth', 'all_objects', 'msg_io'), + get_callables=('persisted_objs', 'persisted_scene_option', 'writable_scenes', 'user_list')) + self.cmd_interpreter.start_thread(self.connected_evt) + def parse_cli(self): """ @@ -297,6 +301,9 @@ def on_connect(self, client, userdata, flags, rc): print("Connected!") print("=====") + + # set event + self.connected_evt.set() else: print(f"Connection error! Result code={rc}") diff --git a/arena/utils/cmd_interpreter.py b/arena/utils/cmd_interpreter.py index 68d383f5..3d000b56 100644 --- a/arena/utils/cmd_interpreter.py +++ b/arena/utils/cmd_interpreter.py @@ -1,6 +1,6 @@ # A simple command interpreter -import cmd, os, json, asyncio +import cmd, os, json, asyncio, threading, time from datetime import date, datetime class ArenaCmdInterpreter(cmd.Cmd): intro = 'Type help or ? to list available commands.\n' @@ -20,10 +20,14 @@ def __init__(self, scene, show_attrs=('config_data', 'scene', 'users', 'auth', ' self._show_attrs = show_attrs self._get_callables = get_callables - # cmd loop; must externally setup a task/thread to run this - def cmd_loop_task(self): + 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() @@ -58,8 +62,6 @@ def do_exit(self, arg): answer = input("This will terminate the ARENA program. Are you sure [Y/N]? ").lower() if answer == "y": print("Exiting...") - loop = asyncio.get_event_loop() - loop.stop() os._exit(0) return True