let sshTerm = null; let sshFit = null; let sshWS = null; let sshResizeTimer = null; function initPage8() { const el = document.getElementById("ssh-terminal"); if (!el || sshTerm) { return; } sshTerm = new Terminal({ cursorBlink: true, scrollback: 2000, fontSize: 14, convertEol: true, theme: { background: "#111111" } }); sshFit = new FitAddon.FitAddon(); sshTerm.loadAddon(sshFit); sshTerm.open(el); sshTerm.focus(); connectSSH(); sshTerm.onData(data => { if (sshWS?.readyState === WebSocket.OPEN) { sshWS.send(JSON.stringify({ type: "input", data: data })); } }); window.addEventListener("resize", resizeSSH); resizeSSH(); } function connectSSH() { sshWS = new WebSocket( "ws://" + location.host + "/api/ssh/ws" ); sshWS.onopen = resizeSSH; sshWS.onmessage = e => { sshTerm?.write(e.data); }; sshWS.onclose = () => { sshWS = null; sshTerm.write( "\r\n\x1b[33m[Connection closed]\x1b[0m\r\n" ); }; } function resizeSSH() { if (!sshFit || !sshTerm) { return; } clearTimeout(sshResizeTimer); sshResizeTimer = setTimeout(() => { sshFit.fit(); if (sshWS?.readyState === WebSocket.OPEN) { sshWS.send(JSON.stringify({ type: "resize", cols: sshTerm.cols, rows: sshTerm.rows })); } }, 100); } function exitPage8() { window.removeEventListener( "resize", resizeSSH ); clearTimeout(sshResizeTimer); sshWS?.close(); sshWS = null; sshTerm?.dispose(); sshTerm = null; sshFit = null; }