From 27f67ce831e01eac905f5336ae9cb2f599a63679 Mon Sep 17 00:00:00 2001 From: YuviPanda Date: Sat, 3 Feb 2024 23:46:01 -0800 Subject: [PATCH] Automatically reconnect if we lose connection This needs much better retry logic, with back-offs and status messages. But fundamentally, it does already work \o/ Fixes https://github.com/jupyterhub/jupyter-remote-desktop-proxy/issues/80 --- js/index.js | 94 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/js/index.js b/js/index.js index 72ae4474..e806b328 100644 --- a/js/index.js +++ b/js/index.js @@ -11,22 +11,8 @@ import RFB from "@novnc/novnc/core/rfb"; import { setupTooltip } from "./tooltip.js"; -// When this function is called we have successfully connected to a server -function connectedToServer() { - status("Connected"); -} - -// This function is called when we are disconnected -function disconnectedFromServer(e) { - if (e.detail.clean) { - status("Disconnected"); - } else { - status("Something went wrong, connection is closed"); - } -} - // Show a status text in the top bar -function status(text) { +function setStatusText(text) { document.getElementById("status").textContent = text; } @@ -36,36 +22,66 @@ function status(text) { let websockifyUrl = new URL("../desktop-websockify/", window.location); websockifyUrl.protocol = window.location.protocol === "https:" ? "wss" : "ws"; -// Creating a new RFB object will start a new connection -const rfb = new RFB( - document.getElementById("screen"), - websockifyUrl.toString(), - {}, -); +/** + * Setup two way clipboard sync with the given rfb + * + * @param {RFB} rfb + */ +function setupClipboardSync(rfb) { + const clipboardText = document.getElementById("clipboard-text"); -// Add listeners to important events from the RFB module -rfb.addEventListener("connect", connectedToServer); -rfb.addEventListener("disconnect", disconnectedFromServer); + // Listen for clipboard events on the remote system, and automatically + // update our local textarea with those values + rfb.addEventListener("clipboard", (e) => { + clipboardText.value = e.detail.text; + }); -// Scale our viewport so the user doesn't have to scroll -rfb.scaleViewport = true; + const clipboardClientChange = () => { + const text = clipboardText.value; + rfb.clipboardPasteFrom(text); + }; + rfb.addEventListener("connect", () => { + console.log("connecting clipboard sync"); + clipboardText.addEventListener("change", clipboardClientChange); + }); + rfb.addEventListener("disconnect", () => { + console.log("disconnecting clipboard sync"); + clipboardText.removeEventListener("change", clipboardClientChange); + }); +} -// Use a CSS variable to set background color -rfb.background = "var(--jupyter-medium-dark-grey)"; +function connect() { + // Creating a new RFB object will start a new connection + const rfb = new RFB( + document.getElementById("screen"), + websockifyUrl.toString(), + {}, + ); -// Clipboard -function clipboardReceive(e) { - document.getElementById("clipboard-text").value = e.detail.text; -} -rfb.addEventListener("clipboard", clipboardReceive); + // Update status when connection is made or broken + rfb.addEventListener("connect", () => { + console.log("connected"); + setStatusText("Connected"); + }); + rfb.addEventListener("disconnect", (e) => { + if (e.detail.clean) { + setStatusText("Disconnected"); + } else { + setStatusText("Something went wrong, connection is closed"); + } + console.log("disconnected"); + connect(); + }); -function clipboardSend() { - const text = document.getElementById("clipboard-text").value; - rfb.clipboardPasteFrom(text); + // Scale our viewport so the user doesn't have to scroll + rfb.scaleViewport = true; + + // Use a CSS variable to set background color + rfb.background = "var(--jupyter-medium-dark-grey)"; + setupClipboardSync(rfb); } -document - .getElementById("clipboard-text") - .addEventListener("change", clipboardSend); + +connect(); setupTooltip( document.getElementById("clipboard-button"),