diff --git a/meshchat.py b/meshchat.py index c84027b..f43201a 100644 --- a/meshchat.py +++ b/meshchat.py @@ -23,6 +23,7 @@ from serial.tools import list_ports import database from src.backend.announce_handler import AnnounceHandler +from src.backend.async_utils import AsyncUtils from src.backend.colour_utils import ColourUtils from src.backend.interface_config_parser import InterfaceConfigParser from src.backend.lxmf_message_fields import LxmfImageField, LxmfFileAttachmentsField, LxmfFileAttachment, LxmfAudioField @@ -2408,7 +2409,7 @@ class ReticulumMeshChat: self.db_upsert_lxmf_message(lxmf_message) # send lxmf message state to all websocket clients - asyncio.run(self.websocket_broadcast(json.dumps({ + AsyncUtils.run_async(self.websocket_broadcast(json.dumps({ "type": "lxmf_message_state_updated", "lxmf_message": self.convert_lxmf_message_to_dict(lxmf_message), }))) diff --git a/src/backend/async_utils.py b/src/backend/async_utils.py new file mode 100644 index 0000000..d20d507 --- /dev/null +++ b/src/backend/async_utils.py @@ -0,0 +1,25 @@ +import asyncio + + +class AsyncUtils: + + # this method allows running the provided async coroutine from within a sync function + # it will run the async function on the existing event loop if available, otherwise it will start a new event loop + @staticmethod + def run_async(coroutine): + + # attempt to get existing event loop + existing_event_loop = None + try: + existing_event_loop = asyncio.get_running_loop() + except RuntimeError: + # 'RuntimeError: no running event loop' + pass + + # if there is an existing event loop running, submit the coroutine to that loop + if existing_event_loop and existing_event_loop.is_running(): + existing_event_loop.create_task(coroutine) + return + + # otherwise start a new event loop to run the coroutine + asyncio.run(coroutine)