/* * RDP-Session-Client: guacamole-common-js <-> /ws/rdp/{host_id}. * * Vollbild: native Browser-Fullscreen-API (Konzept 4.3). * Copy & Paste: bidirektionale Synchronisation ueber Guacamole.Client * onclipboard-Event (Ziel -> Browser) und den `paste`-Browser-Event * (Browser -> Ziel, sendet eine "clipboard"-Instruktion). Wird serverseitig * zusaetzlich blockiert, wenn fuer den Host clipboard_enabled=false ist * (siehe app/rdp_proxy/ws_tunnel.py) -- das UI blendet den Hinweis dann ein. */ (() => { "use strict"; const shell = document.getElementById("session-shell"); const hostId = shell.dataset.hostId; const statusEl = document.getElementById("status"); const displayDiv = document.getElementById("rdp-display"); const proto = window.location.protocol === "https:" ? "wss:" : "ws:"; const width = Math.round(window.innerWidth); const height = Math.round(window.innerHeight - 40); const dpi = Math.round(window.devicePixelRatio * 96) || 96; const tunnelUrl = `${proto}//${window.location.host}/ws/rdp/${hostId}?width=${width}&height=${height}&dpi=${dpi}`; const tunnel = new Guacamole.WebSocketTunnel(tunnelUrl); const client = new Guacamole.Client(tunnel); displayDiv.appendChild(client.getDisplay().getElement()); client.onstatechange = (state) => { // 0=idle,1=connecting,2=waiting,3=connected,4=disconnecting,5=disconnected const labels = ["Idle", "Verbinde ...", "Warte auf Server ...", "Verbunden", "Trenne ...", "Getrennt"]; statusEl.textContent = labels[state] || `Status ${state}`; }; client.onerror = (err) => { statusEl.textContent = "Fehler: " + (err.message || "unbekannt"); }; client.onclipboard = (stream, mimetype) => { if (!mimetype.startsWith("text/")) return; const reader = new Guacamole.StringReader(stream); let data = ""; reader.ontext = (text) => { data += text; }; reader.onend = () => { if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(data).catch(() => {}); } }; }; client.connect(); window.addEventListener("beforeunload", () => client.disconnect()); const mouse = new Guacamole.Mouse(client.getDisplay().getElement()); mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = (mouseState) => { client.sendMouseState(mouseState); }; const keyboard = new Guacamole.Keyboard(document); keyboard.onkeydown = (keysym) => client.sendKeyEvent(1, keysym); keyboard.onkeyup = (keysym) => client.sendKeyEvent(0, keysym); document.addEventListener("paste", (ev) => { const text = (ev.clipboardData || window.clipboardData).getData("text"); if (!text) return; const stream = client.createClipboardStream("text/plain"); const writer = new Guacamole.StringWriter(stream); writer.sendText(text); writer.sendEnd(); }); document.getElementById("fullscreen-btn").addEventListener("click", () => { if (!document.fullscreenElement) { shell.requestFullscreen().catch(() => {}); } else { document.exitFullscreen(); } }); })();