From 841bdcf12dff7eba3b1eb6820d2ac0269f35689f Mon Sep 17 00:00:00 2001 From: Maxime Boissonneault Date: Thu, 17 Jul 2025 19:14:54 +0000 Subject: [PATCH 1/5] allow to have multiple desktop endpoints, and relocate the endpoint to remove -websockify --- js/index.js | 6 ++-- .../server_extension.py | 35 ++++++++++--------- .../setup_websockify.py | 6 ++-- .../templates/index.html | 6 ++-- setup.py | 2 +- tests/test_browser.py | 2 +- 6 files changed, 30 insertions(+), 27 deletions(-) diff --git a/js/index.js b/js/index.js index 10319905..c01b527c 100644 --- a/js/index.js +++ b/js/index.js @@ -42,10 +42,10 @@ function status(text) { document.getElementById("status").textContent = text; } -// This page is served under the /desktop/, and the websockify websocket is served -// under /desktop-websockify/ with the same base url as /desktop/. We resolve it relatively +// This page is served under the /desktopvnc/, and the websockify websocket is served +// under /desktop/ with the same base url as /desktopvnc/. We resolve it relatively // this way. -let websockifyUrl = new URL("../desktop-websockify/", window.location); +let websockifyUrl = new URL("../desktop/", window.location); websockifyUrl.protocol = window.location.protocol === "https:" ? "wss" : "ws"; let retryCount = 0; diff --git a/jupyter_remote_desktop_proxy/server_extension.py b/jupyter_remote_desktop_proxy/server_extension.py index a998f2a7..fb057423 100644 --- a/jupyter_remote_desktop_proxy/server_extension.py +++ b/jupyter_remote_desktop_proxy/server_extension.py @@ -5,7 +5,7 @@ from jupyter_server_proxy.handlers import AddSlashHandler from .handlers import DesktopHandler - +import os HERE = Path(__file__).parent @@ -15,18 +15,21 @@ def load_jupyter_server_extension(server_app): """ base_url = server_app.web_app.settings["base_url"] - server_app.web_app.add_handlers( - ".*", - [ - # Serve our own static files - ( - url_path_join(base_url, "/desktop/static/(.*)"), - AuthenticatedFileHandler, - {"path": (str(HERE / "static"))}, - ), - # To simplify URL mapping, we make sure that /desktop/ always - # has a trailing slash - (url_path_join(base_url, "/desktop"), AddSlashHandler), - (url_path_join(base_url, "/desktop/"), DesktopHandler), - ], - ) + jupyter_remote_desktop_endpoints = os.getenv('JUPYTER_REMOTE_DESKTOP_ENDPOINTS', 'desktopvnc') + endpoints = jupyter_remote_desktop_endpoints.split(',') + for endpoint in endpoints: + server_app.web_app.add_handlers( + ".*", + [ + # Serve our own static files + ( + url_path_join(base_url, f"/{endpoint}/static/(.*)"), + AuthenticatedFileHandler, + {"path": (str(HERE / "static"))}, + ), + # To simplify URL mapping, we make sure that /desktop/ always + # has a trailing slash + (url_path_join(base_url, f"/{endpoint}"), AddSlashHandler), + (url_path_join(base_url, f"/{endpoint}/"), DesktopHandler), + ], + ) diff --git a/jupyter_remote_desktop_proxy/setup_websockify.py b/jupyter_remote_desktop_proxy/setup_websockify.py index e9a56a72..ac4f931a 100644 --- a/jupyter_remote_desktop_proxy/setup_websockify.py +++ b/jupyter_remote_desktop_proxy/setup_websockify.py @@ -56,10 +56,10 @@ def setup_websockify(): 'command': ['/bin/sh', '-c', f'cd {os.getcwd()} && {vnc_command}'], 'timeout': 30, 'new_browser_window': True, - # We want the launcher entry to point to /desktop/, not to /desktop-websockify/ - # /desktop/ is the user facing URL, while /desktop-websockify/ now *only* serves + # We want the launcher entry to point to /desktopvnc/, not to /desktop/ + # /desktop/ is the user facing URL, while /desktop/ now *only* serves # websockets. - "launcher_entry": {"title": "Desktop", "path_info": "desktop"}, + "launcher_entry": {"title": "Desktop", "path_info": "desktopvnc"}, "unix_socket": True, "raw_socket_proxy": True, } diff --git a/jupyter_remote_desktop_proxy/templates/index.html b/jupyter_remote_desktop_proxy/templates/index.html index 38b88c09..7eb49bbf 100644 --- a/jupyter_remote_desktop_proxy/templates/index.html +++ b/jupyter_remote_desktop_proxy/templates/index.html @@ -13,13 +13,13 @@ Chrome Frame. --> - +
- + diff --git a/setup.py b/setup.py index 7dc4cc44..a18aa124 100644 --- a/setup.py +++ b/setup.py @@ -60,7 +60,7 @@ def run(self): description="Run a desktop environments on Jupyter", entry_points={ 'jupyter_serverproxy_servers': [ - 'desktop-websockify = jupyter_remote_desktop_proxy.setup_websockify:setup_websockify', + 'desktop = jupyter_remote_desktop_proxy.setup_websockify:setup_websockify', ] }, install_requires=[ diff --git a/tests/test_browser.py b/tests/test_browser.py index 8ca052f6..927acb6a 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -49,7 +49,7 @@ def test_desktop(browser): with page.expect_popup() as page1_info: page.get_by_text("Desktop [↗]").click() page1 = page1_info.value - page1.wait_for_url(f"{JUPYTER_HOST}/desktop/") + page1.wait_for_url(f"{JUPYTER_HOST}/desktopvnc/") expect(page1.get_by_text("Status: Connected")).to_be_visible() expect(page1.locator("canvas")).to_be_visible() From f14de6ff4606fe99a598db8bc7bcb1ec52040532 Mon Sep 17 00:00:00 2001 From: Maxime Boissonneault Date: Thu, 17 Jul 2025 19:39:20 +0000 Subject: [PATCH 2/5] make the websockifyUrl depend on the original location to make it customizable --- js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/index.js b/js/index.js index c01b527c..24a4c7d0 100644 --- a/js/index.js +++ b/js/index.js @@ -45,7 +45,7 @@ function status(text) { // This page is served under the /desktopvnc/, and the websockify websocket is served // under /desktop/ with the same base url as /desktopvnc/. We resolve it relatively // this way. -let websockifyUrl = new URL("../desktop/", window.location); +let websockifyUrl = new URL(window.location.pathname.replace(/vnc\/+$/, "/"), window.location); websockifyUrl.protocol = window.location.protocol === "https:" ? "wss" : "ws"; let retryCount = 0; From ac6334505df77d6ce701be611ec17d93bc4cd57c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 17 Jul 2025 19:41:28 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- js/index.js | 5 ++++- jupyter_remote_desktop_proxy/server_extension.py | 7 +++++-- jupyter_remote_desktop_proxy/templates/index.html | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/js/index.js b/js/index.js index 24a4c7d0..c9ea176c 100644 --- a/js/index.js +++ b/js/index.js @@ -45,7 +45,10 @@ function status(text) { // This page is served under the /desktopvnc/, and the websockify websocket is served // under /desktop/ with the same base url as /desktopvnc/. We resolve it relatively // this way. -let websockifyUrl = new URL(window.location.pathname.replace(/vnc\/+$/, "/"), window.location); +let websockifyUrl = new URL( + window.location.pathname.replace(/vnc\/+$/, "/"), + window.location, +); websockifyUrl.protocol = window.location.protocol === "https:" ? "wss" : "ws"; let retryCount = 0; diff --git a/jupyter_remote_desktop_proxy/server_extension.py b/jupyter_remote_desktop_proxy/server_extension.py index fb057423..b31751fd 100644 --- a/jupyter_remote_desktop_proxy/server_extension.py +++ b/jupyter_remote_desktop_proxy/server_extension.py @@ -1,3 +1,4 @@ +import os from pathlib import Path from jupyter_server.base.handlers import AuthenticatedFileHandler @@ -5,7 +6,7 @@ from jupyter_server_proxy.handlers import AddSlashHandler from .handlers import DesktopHandler -import os + HERE = Path(__file__).parent @@ -15,7 +16,9 @@ def load_jupyter_server_extension(server_app): """ base_url = server_app.web_app.settings["base_url"] - jupyter_remote_desktop_endpoints = os.getenv('JUPYTER_REMOTE_DESKTOP_ENDPOINTS', 'desktopvnc') + jupyter_remote_desktop_endpoints = os.getenv( + 'JUPYTER_REMOTE_DESKTOP_ENDPOINTS', 'desktopvnc' + ) endpoints = jupyter_remote_desktop_endpoints.split(',') for endpoint in endpoints: server_app.web_app.add_handlers( diff --git a/jupyter_remote_desktop_proxy/templates/index.html b/jupyter_remote_desktop_proxy/templates/index.html index 7eb49bbf..ce875924 100644 --- a/jupyter_remote_desktop_proxy/templates/index.html +++ b/jupyter_remote_desktop_proxy/templates/index.html @@ -13,7 +13,10 @@ Chrome Frame. --> - + From d586cbf2fb96a80018edb53b7980ef52c9e3a841 Mon Sep 17 00:00:00 2001 From: Maxime Boissonneault Date: Fri, 18 Jul 2025 13:07:18 +0000 Subject: [PATCH 4/5] the templates rely on the desktop endpoint to always be there, and the suffix vnc too --- jupyter_remote_desktop_proxy/server_extension.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jupyter_remote_desktop_proxy/server_extension.py b/jupyter_remote_desktop_proxy/server_extension.py index b31751fd..a2fd1858 100644 --- a/jupyter_remote_desktop_proxy/server_extension.py +++ b/jupyter_remote_desktop_proxy/server_extension.py @@ -17,22 +17,22 @@ def load_jupyter_server_extension(server_app): base_url = server_app.web_app.settings["base_url"] jupyter_remote_desktop_endpoints = os.getenv( - 'JUPYTER_REMOTE_DESKTOP_ENDPOINTS', 'desktopvnc' + 'JUPYTER_REMOTE_DESKTOP_ENDPOINTS', '' ) - endpoints = jupyter_remote_desktop_endpoints.split(',') + endpoints = ['desktop'] + jupyter_remote_desktop_endpoints.split(',') for endpoint in endpoints: server_app.web_app.add_handlers( ".*", [ # Serve our own static files ( - url_path_join(base_url, f"/{endpoint}/static/(.*)"), + url_path_join(base_url, f"/{endpoint}vnc/static/(.*)"), AuthenticatedFileHandler, {"path": (str(HERE / "static"))}, ), # To simplify URL mapping, we make sure that /desktop/ always # has a trailing slash - (url_path_join(base_url, f"/{endpoint}"), AddSlashHandler), - (url_path_join(base_url, f"/{endpoint}/"), DesktopHandler), + (url_path_join(base_url, f"/{endpoint}vnc"), AddSlashHandler), + (url_path_join(base_url, f"/{endpoint}vnc/"), DesktopHandler), ], ) From 0a931bdbe25ee619a5e74852e8f6677f1d1ccdc5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:10:08 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- jupyter_remote_desktop_proxy/server_extension.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jupyter_remote_desktop_proxy/server_extension.py b/jupyter_remote_desktop_proxy/server_extension.py index a2fd1858..d15db893 100644 --- a/jupyter_remote_desktop_proxy/server_extension.py +++ b/jupyter_remote_desktop_proxy/server_extension.py @@ -16,9 +16,7 @@ def load_jupyter_server_extension(server_app): """ base_url = server_app.web_app.settings["base_url"] - jupyter_remote_desktop_endpoints = os.getenv( - 'JUPYTER_REMOTE_DESKTOP_ENDPOINTS', '' - ) + jupyter_remote_desktop_endpoints = os.getenv('JUPYTER_REMOTE_DESKTOP_ENDPOINTS', '') endpoints = ['desktop'] + jupyter_remote_desktop_endpoints.split(',') for endpoint in endpoints: server_app.web_app.add_handlers(