clients attempt reconnection after socket close
authorAndrew Lorimer <andrew@lorimer.id.au>
Sat, 22 May 2021 06:50:38 +0000 (16:50 +1000)
committerAndrew Lorimer <andrew@lorimer.id.au>
Sat, 22 May 2021 06:50:38 +0000 (16:50 +1000)
ppt_control/ppt_control_obs.py
ppt_control/static/index.html
ppt_control/static/ppt-control.js
index aa2e44b7bb72e42a8f7634127404b0dae7102d0f..640d586856b513f2b6c2cce40c900abbce2a927d 100755 (executable)
@@ -4,6 +4,7 @@ import obspython as obs
 import asyncio\r
 import websockets\r
 import threading\r
 import asyncio\r
 import websockets\r
 import threading\r
+import logging, logging.handlers\r
 from time import sleep\r
 \r
 PORT_DEFAULT = 5678\r
 from time import sleep\r
 \r
 PORT_DEFAULT = 5678\r
@@ -30,12 +31,18 @@ HOTKEY_DESC_LAST = 'Last PowerPoint slide'
 HOTKEY_DESC_BLACK = 'Black PowerPoint slide'\r
 HOTKEY_DESC_WHITE = 'White PowerPoint slide'\r
 \r
 HOTKEY_DESC_BLACK = 'Black PowerPoint slide'\r
 HOTKEY_DESC_WHITE = 'White PowerPoint slide'\r
 \r
+LOG_LEVEL = logging.DEBUG\r
+\r
 global cmd\r
 global attempts\r
 global cmd\r
 global attempts\r
+global logger\r
 cmd = ""\r
 hostname = HOSTNAME_DEFAULT\r
 port = PORT_DEFAULT\r
 attempts = 0\r
 cmd = ""\r
 hostname = HOSTNAME_DEFAULT\r
 port = PORT_DEFAULT\r
 attempts = 0\r
+logger = None\r
+\r
+logging.basicConfig()\r
 \r
 async def communicate():\r
     async with websockets.connect("ws://%s:%s" % (hostname, port), ping_interval=None) as websocket:\r
 \r
 async def communicate():\r
     async with websockets.connect("ws://%s:%s" % (hostname, port), ping_interval=None) as websocket:\r
@@ -48,24 +55,27 @@ async def communicate():
                     cmd = ""\r
                     await websocket.send('{"action": "%s"}' % cmd_temp)\r
                 except websockets.ConnectionClosed as exc:\r
                     cmd = ""\r
                     await websocket.send('{"action": "%s"}' % cmd_temp)\r
                 except websockets.ConnectionClosed as exc:\r
+                    logger.info("Failed to send command {}: {}".format(cmd_temp, str(exc)))\r
+                    cmd = cmd_temp\r
                     attempts += 1\r
                     if attempts == 4:\r
                     attempts += 1\r
                     if attempts == 4:\r
-                        print("Failed to send command after {} attempts - aborting connection".format(attempts))\r
+                        logger.info("Failed to send command {} after {} attempts - aborting connection".format(cmd_temp, attempts))\r
                         attempts = 0\r
                         cmd = ""\r
                         attempts = 0\r
                         cmd = ""\r
-                        raise websockets.exceptions.ConnectionClosedError(1006, "Sending command failed after {} attempts".format(attempts))\r
+                        break\r
             await asyncio.sleep(0.05 + 0.5*attempts**2)\r
 \r
 def run_ws():\r
     while True:\r
             await asyncio.sleep(0.05 + 0.5*attempts**2)\r
 \r
 def run_ws():\r
     while True:\r
+        logger.debug("Attempting to connect")\r
         try:\r
             asyncio.set_event_loop(asyncio.new_event_loop())\r
             asyncio.get_event_loop().run_until_complete(communicate())\r
         try:\r
             asyncio.set_event_loop(asyncio.new_event_loop())\r
             asyncio.get_event_loop().run_until_complete(communicate())\r
-        except (OSError, websockets.exceptions.ConnectionClosedError):\r
+        except (OSError, websockets.exceptions.ConnectionClosedError) as e:\r
             # No server available - just keep trying\r
             pass\r
         except Exception as e:\r
             # No server available - just keep trying\r
             pass\r
         except Exception as e:\r
-            print("Failed to connect to websocket: {} - {}".format(type(e), e))\r
+            logger.warning("Failed to connect to websocket: {} - {}".format(type(e), e))\r
         finally:\r
             sleep(1)\r
 \r
         finally:\r
             sleep(1)\r
 \r
@@ -79,6 +89,7 @@ def script_load(settings):
     global hotkey_id_last\r
     global hotkey_id_black\r
     global hotkey_id_white\r
     global hotkey_id_last\r
     global hotkey_id_black\r
     global hotkey_id_white\r
+    global logger\r
 \r
     hotkey_id_first = register_and_load_hotkey(settings, HOTKEY_NAME_FIRST, HOTKEY_DESC_FIRST, first_slide)\r
     hotkey_id_prev = register_and_load_hotkey(settings, HOTKEY_NAME_PREV, HOTKEY_DESC_PREV, prev_slide)\r
 \r
     hotkey_id_first = register_and_load_hotkey(settings, HOTKEY_NAME_FIRST, HOTKEY_DESC_FIRST, first_slide)\r
     hotkey_id_prev = register_and_load_hotkey(settings, HOTKEY_NAME_PREV, HOTKEY_DESC_PREV, prev_slide)\r
@@ -87,10 +98,20 @@ def script_load(settings):
     hotkey_id_black = register_and_load_hotkey(settings, HOTKEY_NAME_BLACK, HOTKEY_DESC_BLACK, black)\r
     hotkey_id_white = register_and_load_hotkey(settings, HOTKEY_NAME_WHITE, HOTKEY_DESC_WHITE, white)\r
 \r
     hotkey_id_black = register_and_load_hotkey(settings, HOTKEY_NAME_BLACK, HOTKEY_DESC_BLACK, black)\r
     hotkey_id_white = register_and_load_hotkey(settings, HOTKEY_NAME_WHITE, HOTKEY_DESC_WHITE, white)\r
 \r
+    # Set up logging\r
+    log_formatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-7.7s]  %(message)s")\r
+    logger = logging.getLogger("ppt_control_obs")\r
+    logger.setLevel(LOG_LEVEL)\r
+    logger.propagate = False\r
+    console_handler = logging.StreamHandler()\r
+    console_handler.setFormatter(log_formatter)\r
+    console_handler.setLevel(LOG_LEVEL)\r
+    logger.addHandler(console_handler)\r
+\r
     ws_daemon = threading.Thread(name="ws_daemon", target=run_ws)\r
     ws_daemon.setDaemon(True)\r
     ws_daemon.start()\r
     ws_daemon = threading.Thread(name="ws_daemon", target=run_ws)\r
     ws_daemon.setDaemon(True)\r
     ws_daemon.start()\r
-    print("Started websocket client")\r
+    logger.info("Started websocket client")\r
 \r
 def script_unload():\r
     obs.obs_hotkey_unregister(first_slide)\r
 \r
 def script_unload():\r
     obs.obs_hotkey_unregister(first_slide)\r
index b19415f6cf566d9a9daf24b5246e6057de7f02dc..21d08afbd0d70c91900f26c1dc8a0ee8d40aacfc 100755 (executable)
@@ -38,7 +38,7 @@
                        <input type="checkbox" checked="true" id="show_next">Show next slide</input>\r
                        <input type="checkbox" checked="true" id="shortcuts">Keyboard shortcuts</input>\r
 \r
                        <input type="checkbox" checked="true" id="show_next">Show next slide</input>\r
                        <input type="checkbox" checked="true" id="shortcuts">Keyboard shortcuts</input>\r
 \r
-                       <p class="users">Not connected</p>\r
+                       <p class="status_text">Disconnected</p>\r
                </div>\r
         </div>\r
 \r
                </div>\r
         </div>\r
 \r
index 2265ca3f25aa30e8f4e45b3bcae1715107ce44c4..f884d90a8cfef532b74bbaf6064db4c953cc5ce4 100644 (file)
@@ -2,25 +2,6 @@ var DEFAULT_TITLE = "ppt-control"
 var preloaded = false;
 var preload = [];
 
 var preloaded = false;
 var preload = [];
 
-function imageRefresh(id) {
-    img = document.getElementById(id);
-    var d = new Date;
-    var http = img.src;
-    if (http.indexOf("?t=") != -1) { http = http.split("?t=")[0]; } 
-    img.src = http + '?t=' + d.getTime();
-}
-
-function startWebsocket() {
-    ws = new WebSocket("ws://" + window.location.host + ":5678/");
-    ws.onclose = function(){
-        //websocket = null;
-        setTimeout(function(){startWebsocket()}, 10000);
-    }
-    return ws;
-}
-
-var websocket = startWebsocket();
-
 var prev = document.querySelector('#prev'),
     next = document.querySelector('#next'),
     first = document.querySelector('#first'),
 var prev = document.querySelector('#prev'),
     next = document.querySelector('#next'),
     first = document.querySelector('#first'),
@@ -30,7 +11,7 @@ var prev = document.querySelector('#prev'),
     slide_label = document.querySelector('#slide_label'),
     current = document.querySelector('#current'),
     total = document.querySelector('#total'),
     slide_label = document.querySelector('#slide_label'),
     current = document.querySelector('#current'),
     total = document.querySelector('#total'),
-    users = document.querySelector('.users'),
+    status_text = document.querySelector('.status_text'),
     current_img = document.querySelector('#current_img'),
     next_img = document.querySelector('#next_img'),
     current_div = document.querySelector('#current_div'),
     current_img = document.querySelector('#current_img'),
     next_img = document.querySelector('#next_img'),
     current_div = document.querySelector('#current_div'),
@@ -41,6 +22,23 @@ var prev = document.querySelector('#prev'),
     show_next = document.querySelector('#show_next'),
     shortcuts = document.querySelector('#shortcuts');
 
     show_next = document.querySelector('#show_next'),
     shortcuts = document.querySelector('#shortcuts');
 
+
+function startWebsocket() {
+    console.log("Attempting to connect")
+    ws = new WebSocket("ws://" + window.location.host + ":5678/");
+    ws.onmessage = receive_message;
+    ws.onclose = function(){
+        ws = null;
+        setTimeout(function(){websocket = startWebsocket()}, 1000);
+    }
+    if (ws.readyState !== WebSocket.OPEN) {
+      disconnect()
+    }
+    return ws;
+}
+
+var websocket = startWebsocket();
+
 prev.onclick = function (event) {
     websocket.send(JSON.stringify({action: 'prev'}));
 }
 prev.onclick = function (event) {
     websocket.send(JSON.stringify({action: 'prev'}));
 }
@@ -161,31 +159,25 @@ document.addEventListener('keydown', function (e) {
        }
 });
 
        }
 });
 
-function sleep(ms) {
-      return new Promise(resolve => setTimeout(resolve, ms));
-}
-
 function disconnect() {
 function disconnect() {
-       document.title = DEFAULT_TITLE;
+  console.log("Disconnecting")
+    document.title = DEFAULT_TITLE;
     current_img.src = "/black.jpg";
     next_img.src = "/black.jpg";
     current_img.src = "/black.jpg";
     next_img.src = "/black.jpg";
-    users.textContent = "Connection to PowerPoint failed";
-}
-
-function update_current() {
+    status_text.textContent = "Disconnected";
+    total.textContent = "?";
+    current.value = "";
 }
 
 }
 
-function update_next() {
-}
-
-websocket.onmessage = function (event) {
+function receive_message(event) {
     data = JSON.parse(event.data);
     switch (data.type) {
         case 'state':
             if (data.connected == "0" || data.connected == 0) {
     data = JSON.parse(event.data);
     switch (data.type) {
         case 'state':
             if (data.connected == "0" || data.connected == 0) {
-                               console.log("Disconnected");
                disconnect();
                break;
                disconnect();
                break;
+            } else {
+              status_text.textContent = "Connected";
             }
             var d = new Date;
             if (show_current.checked) {
             }
             var d = new Date;
             if (show_current.checked) {
@@ -225,8 +217,6 @@ websocket.onmessage = function (event) {
                for (let i=1; i<=Number(total.textContent); i++) {
                        image.src = "/cache/" + i + ".jpg";
                        preload.push(image);
                for (let i=1; i<=Number(total.textContent); i++) {
                        image.src = "/cache/" + i + ".jpg";
                        preload.push(image);
-               console.log("Preloaded " + total.textContent);
-                       //sleep(0.5)
                }
                preloaded = true;
        }
                }
                preloaded = true;
        }