From: Andrew Lorimer Date: Sat, 1 May 2021 12:55:08 +0000 (+1000) Subject: failsafe websocket client on OBS script X-Git-Tag: v0.0.1~2 X-Git-Url: https://git.lorimer.id.au/ppt-control.git/diff_plain/ee4eafe3cd5e26aaf93702af45cd58eee1b90d03 failsafe websocket client on OBS script --- diff --git a/ppt_control.py b/ppt_control.py index 2e0cc3d..5e8bdfa 100755 --- a/ppt_control.py +++ b/ppt_control.py @@ -185,26 +185,16 @@ def run_ws(): asyncio.get_event_loop().run_forever() def start_server(): - #STATE["current"] = current_slide() http_daemon = threading.Thread(name="http_daemon", target=run_http) http_daemon.setDaemon(True) http_daemon.start() print("Started HTTP server") - - #run_ws() ws_daemon = threading.Thread(name="ws_daemon", target=run_ws) ws_daemon.setDaemon(True) ws_daemon.start() print("Started websocket server") - #try: - # ws_daemon.start() - # http_daemon.start() - #except (KeyboardInterrupt, SystemExit): - # cleanup_stop_thread() - # sys.exit() - class Slideshow: def __init__(self, instance): self.instance = instance diff --git a/ppt_control_obs.py b/ppt_control_obs.py index d9ab70d..e36957e 100755 --- a/ppt_control_obs.py +++ b/ppt_control_obs.py @@ -4,6 +4,10 @@ import obspython as obs import asyncio import websockets import threading +from time import sleep + +PORT_DEFAULT = 5678 +HOSTNAME_DEFAULT = "localhost" hotkey_id_first = None hotkey_id_prev = None @@ -26,23 +30,43 @@ HOTKEY_DESC_LAST = 'Last PowerPoint slide' HOTKEY_DESC_BLACK = 'Black PowerPoint slide' HOTKEY_DESC_WHITE = 'White PowerPoint slide' -global cmd +global cmd +global attempts cmd = "" +hostname = HOSTNAME_DEFAULT +port = PORT_DEFAULT +attempts = 0 async def communicate(): - global cmd - async with websockets.connect("ws://10.0.0.93:5678", ping_interval=None) as websocket: + async with websockets.connect("ws://%s:%s" % (hostname, port), ping_interval=None) as websocket: + global cmd + global attempts while True: if cmd: - await websocket.send("{\"action\": \"" + cmd + "\"}") - cmd = "" - await asyncio.sleep(0.05) + try: + await websocket.send('{"action": "%s"}' % cmd) + cmd = "" + except websockets.ConnectionClosed as exc: + attempts += 1 + if attempts == 4: + print("Failed to send command after {} attempts - aborting connection".format(attempts)) + attempts = 0 + cmd = "" + raise websockets.exceptions.ConnectionClosedError(1006, "Sending command failed after {} attempts".format(attempts)) + await asyncio.sleep(0.05 + 0.5*attempts**2) def run_ws(): - asyncio.set_event_loop(asyncio.new_event_loop()) - asyncio.get_event_loop().run_until_complete(communicate()) - - + while True: + try: + asyncio.set_event_loop(asyncio.new_event_loop()) + asyncio.get_event_loop().run_until_complete(communicate()) + except (OSError, websockets.exceptions.ConnectionClosedError): + # No server available - just keep trying + pass + except Exception as e: + print("Failed to connect to websocket: {} - {}".format(type(e), e)) + finally: + sleep(1) #------------------------------------------------------------ # global functions for script plugins @@ -61,6 +85,7 @@ def script_load(settings): hotkey_id_last = register_and_load_hotkey(settings, HOTKEY_NAME_LAST, HOTKEY_DESC_LAST, last_slide) hotkey_id_black = register_and_load_hotkey(settings, HOTKEY_NAME_BLACK, HOTKEY_DESC_BLACK, black) hotkey_id_white = register_and_load_hotkey(settings, HOTKEY_NAME_WHITE, HOTKEY_DESC_WHITE, white) + ws_daemon = threading.Thread(name="ws_daemon", target=run_ws) ws_daemon.setDaemon(True) ws_daemon.start() @@ -83,20 +108,26 @@ def script_save(settings): save_hotkey(settings, HOTKEY_NAME_WHITE, hotkey_id_white) def script_description(): - return "ppt-control client\nHotkeys for controlling PowerPoint slides using websockets" + return """ppt-control client + + Provides hotkeys for controlling PowerPoint slides using websockets. + Go to OBS settings -> Hotkeys to change hotkeys (none set by default).""" def script_defaults(settings): - obs.obs_data_set_default_int(settings, 'port', 5678) + obs.obs_data_set_default_string(settings, 'hostname', HOSTNAME_DEFAULT) + obs.obs_data_set_default_int(settings, 'port', PORT_DEFAULT) def script_properties(): props = obs.obs_properties_create() - obs.obs_properties_add_int(props, "port", "Websocket port: ", 0, 9999, 1) + obs.obs_properties_add_text(props, "hostname", "Hostname: ", obs.OBS_TEXT_DEFAULT) + obs.obs_properties_add_int(props, "port", "Port: ", 0, 9999, 1) return props def script_update(settings): global port port = obs.obs_data_get_int(settings, "port") + hostname = obs.obs_data_get_string(settings, "hostname") def register_and_load_hotkey(settings, name, description, callback): hotkey_id = obs.obs_hotkey_register_frontend(name, description, callback)