diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index 858ba1b6..8eecaf7f 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -254,6 +254,10 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins async def __ws_ping_handler(self, ws: WsSession, _: dict) -> None: await ws.send_event("pong", {}) + @exposed_ws(0) + async def __ws_bin_ping_handler(self, ws: WsSession, _: bytes) -> None: + await ws.send_bin(255, b"") # Ping-pong + # ===== SYSTEM STUFF def run(self, **kwargs: Any) -> None: # type: ignore # pylint: disable=arguments-differ diff --git a/web/share/js/kvm/session.js b/web/share/js/kvm/session.js index 2133a885..a540a94b 100644 --- a/web/share/js/kvm/session.js +++ b/web/share/js/kvm/session.js @@ -301,8 +301,16 @@ export function Session() { if (http.status === 200) { __ws = new WebSocket(tools.makeWsUrl("api/ws")); __ws.sendHidEvent = (event) => __sendHidEvent(__ws, event.event_type, event.event); + __ws.binaryType = "arraybuffer"; __ws.onopen = __wsOpenHandler; - __ws.onmessage = __wsMessageHandler; + __ws.onmessage = async (event) => { + if (typeof event.data === "string") { + event = JSON.parse(event.data); + __wsJsonHandler(event.event_type, event.event); + } else { // Binary + __wsBinHandler(event.data); + } + }; __ws.onerror = __wsErrorHandler; __ws.onclose = __wsCloseHandler; } else if (http.status === 401 || http.status === 403) { @@ -369,33 +377,37 @@ export function Session() { __ping_timer = setInterval(__pingServer, 1000); }; - var __wsMessageHandler = function(event) { - // tools.debug("Session: received socket data:", event.data); - let data = JSON.parse(event.data); - switch (data.event_type) { - case "pong": __missed_heartbeats = 0; break; - case "info": __setInfoState(data.event); break; - case "gpio": __gpio.setState(data.event); break; - case "hid": __hid.setState(data.event); break; - case "hid_keymaps": __paste.setState(data.event); break; - case "atx": __atx.setState(data.event); break; - case "streamer": __streamer.setState(data.event); break; - case "ocr": __ocr.setState(data.event); break; + var __wsBinHandler = function(data) { + data = new Uint8Array(data); + if (data[0] === 255) { // Pong + __missed_heartbeats = 0; + } + }; + + var __wsJsonHandler = function(event_type, event) { + switch (event_type) { + case "info": __setInfoState(event); break; + case "gpio": __gpio.setState(event); break; + case "hid": __hid.setState(event); break; + case "hid_keymaps": __paste.setState(event); break; + case "atx": __atx.setState(event); break; + case "streamer": __streamer.setState(event); break; + case "ocr": __ocr.setState(event); break; case "msd": - if (data.event.online === false) { + if (event.online === false) { __switch.setMsdConnected(false); - } else if (data.event.drive !== undefined) { - __switch.setMsdConnected(data.event.drive.connected); + } else if (event.drive !== undefined) { + __switch.setMsdConnected(event.drive.connected); } - __msd.setState(data.event); + __msd.setState(event); break; case "switch": - if (data.event.model) { - __atx.setHasSwitch(data.event.model.ports.length > 0); + if (event.model) { + __atx.setHasSwitch(event.model.ports.length > 0); } - __switch.setState(data.event); + __switch.setState(event); break; } }; @@ -442,7 +454,7 @@ export function Session() { if (__missed_heartbeats >= 15) { throw new Error("Too many missed heartbeats"); } - __ws.send("{\"event_type\": \"ping\", \"event\": {}}"); + __ws.send(new Uint8Array([0])); } catch (ex) { __wsErrorHandler(ex.message); } diff --git a/web/share/js/kvm/stream_media.js b/web/share/js/kvm/stream_media.js index a0ea323a..0e81c7d9 100644 --- a/web/share/js/kvm/stream_media.js +++ b/web/share/js/kvm/stream_media.js @@ -87,7 +87,8 @@ export function MediaStreamer(__setActive, __setInactive, __setInfo, __orient) { __ws.onclose = __wsCloseHandler; __ws.onmessage = async (event) => { if (typeof event.data === "string") { - __wsJsonHandler(JSON.parse(event.data)); + event = JSON.parse(event.data); + __wsJsonHandler(event.event_type, event.event); } else { // Binary await __wsBinHandler(event.data); } @@ -153,9 +154,9 @@ export function MediaStreamer(__setActive, __setInactive, __setInfo, __orient) { } }; - var __wsJsonHandler = function(event) { - if (event.event_type === "media") { - __decoderCreate(event.event.video); + var __wsJsonHandler = function(event_type, event) { + if (event_type === "media") { + __decoderCreate(event.video); } };