gommand/static/start-interactive.js

159 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

document.addEventListener("DOMContentLoaded", function () {
const input = document.getElementById("command-input");
// We assume your normal terminal UI is in the element with id "terminal".
const normalTerminal = document.getElementById("terminal");
let interactiveWS = null;
let interactiveMode = false;
const ansi_up = new AnsiUp;
input.addEventListener("keydown", function (event) {
if (!interactiveMode && event.key === "Enter") {
const command = input.value.trim();
if (command === "start-interactive") {
startInteractiveSession();
input.value = "";
event.preventDefault();
return;
}
// Otherwise, your normal HTTP submission…
}
});
// Helper: get ?ip=…&port=… from the current location
function getQueryParam(name) {
return new URLSearchParams(window.location.search).get(name);
}
function makeWsUrl() {
const proxyIp = getQueryParam("ip"); // "10.0.0.42" if you came via /proxyAgent
const proxyPort = getQueryParam("port"); // "8080"
const usingProxy = proxyIp && proxyPort; // truthy only in that case
if (usingProxy) {
// Build ws(s)://<main-server>/proxyAgent/terminal?ip=…&port=…
const u = new URL("/proxyAgent/terminal", window.location);
u.searchParams.set("ip", proxyIp);
u.searchParams.set("port", proxyPort);
u.protocol = u.protocol === "https:" ? "wss:" : "ws:";
return u.toString();
}
// Fallback: open directly on the agent were already on
const u = new URL("/terminal", window.location);
u.protocol = u.protocol === "https:" ? "wss:" : "ws:";
return u.toString();
}
function startInteractiveSession() {
interactiveMode = true;
// Hide the normal terminal and input.
normalTerminal.style.display = "none";
input.style.display = "none";
// Create a new container for xterm.js.
const xtermContainer = document.createElement("div");
xtermContainer.id = "xterm-container";
xtermContainer.style.position = "fixed";
xtermContainer.style.top = "0";
xtermContainer.style.left = "0";
xtermContainer.style.width = window.innerWidth + "px";
xtermContainer.style.height = window.innerHeight + "px";
xtermContainer.style.zIndex = "1000";
document.body.appendChild(xtermContainer);
const term = new Terminal({
cursorBlink: true,
cursorStyle: 'block',
scrollback: 1000,
fontSize: 18,
theme: {
background: "#222",
foreground: "#eee"
}
});
const fitAddon = new FitAddon.FitAddon();
term.loadAddon(fitAddon);
term.open(xtermContainer);
setTimeout(() => {
fitAddon.fit();
term.focus();
console.log("Initial fit: container width =", xtermContainer.offsetWidth, "cols =", term.cols);
}, 100);
interactiveWS = new WebSocket(makeWsUrl());
// interactiveWS = new WebSocket("ws://" + location.host + "/terminal");
interactiveWS.binaryType = "arraybuffer";
interactiveWS.onopen = function () {
sendResize();
};
interactiveWS.onmessage = function (event) {
const text = new TextDecoder("utf-8").decode(event.data);
term.write(text);
};
interactiveWS.onclose = function () {
interactiveMode = false;
term.write("\r\n--- Interactive session ended ---\r\n");
if (xtermContainer.parentNode) {
xtermContainer.parentNode.removeChild(xtermContainer);
}
window.removeEventListener("resize", handleResize);
normalTerminal.style.display = "block";
input.style.display = "block";
input.focus();
};
interactiveWS.onerror = function (err) {
term.write("\r\n--- Error in interactive session ---\r\n");
console.error("Interactive WS error:", err);
interactiveMode = false;
if (xtermContainer.parentNode) {
xtermContainer.parentNode.removeChild(xtermContainer);
}
window.removeEventListener("resize", handleResize);
normalTerminal.style.display = "block";
input.style.display = "block";
};
term.onData(function (data) {
if (data === "\x04") {
term.write("\r\n--- Exiting interactive session ---\r\n");
interactiveWS.close();
} else {
interactiveWS.send(data);
}
});
function handleResize() {
const newWidth = window.innerWidth;
const newHeight = window.innerHeight;
xtermContainer.style.width = newWidth + "px";
xtermContainer.style.height = newHeight + "px";
console.log("Resizing: new width =", newWidth, "new height =", newHeight);
fitAddon.fit();
sendResize();
}
window.addEventListener("resize", handleResize);
// Send a resize message using a custom control prefix (0xFF).
function sendResize() {
const resizeData = {
type: "resize",
cols: term.cols,
rows: term.rows
};
const jsonStr = JSON.stringify(resizeData);
const encoder = new TextEncoder();
const jsonBuffer = encoder.encode(jsonStr);
// Create a Uint8Array with one extra byte for the prefix.
const buffer = new Uint8Array(jsonBuffer.length + 1);
buffer[0] = 0xFF; // Control prefix.
buffer.set(jsonBuffer, 1);
interactiveWS.send(buffer.buffer);
console.log("Sent resize: cols =", term.cols, "rows =", term.rows);
}
}
});