gommand/static/start-interactive.js

163 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 loc = window.location; // shortcut
const proto = loc.protocol === "https:" ? "wss:" : "ws:";
// Pathbased scheme: /proxyAgent/<key>/...
// Split pathname: ["", "proxyAgent", "<key>", ...]
const parts = loc.pathname.split("/");
if (parts.length >= 3 && parts[1] === "proxyAgent" && parts[2]) {
const agentKey = parts[2]; // e.g. "192.168.0.12:43211"
const ws = new URL(`/proxyAgent/${agentKey}/terminal`, loc);
ws.protocol = proto;
return ws.toString();
}
// Direct fallback: same host, /terminal
const ws = new URL("/terminal", loc);
ws.protocol = proto;
return ws.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);
}
}
});