connectiopn fix round 2 4
This commit is contained in:
@ -33,8 +33,24 @@
|
||||
function b64encode(str) {
|
||||
return btoa(unescape(encodeURIComponent(str)));
|
||||
}
|
||||
function b64decode(b64) {
|
||||
return decodeURIComponent(escape(atob(b64)));
|
||||
// Bugfix: NICHT ueber decodeURIComponent(escape(atob(...))) als JS-String
|
||||
// dekodieren. Jedes "output"-Frame entspricht genau einem Chunk aus
|
||||
// process.stdout.read() auf dem Server (app/ssh_proxy/terminal_ws.py) --
|
||||
// ein Mehrbyte-UTF-8-Zeichen (Umlaute, Box-Drawing-Zeichen, Emoji in
|
||||
// Banner/Prompt/htop etc.) kann dabei GENAU AN DER CHUNK-GRENZE
|
||||
// auseinandergerissen werden. decodeURIComponent() wirft dann einen
|
||||
// "URI malformed"-Fehler fuer diesen einen Chunk (siehe
|
||||
// static/js/admin.js::createSshPlayer fuer die noch schwerwiegendere
|
||||
// Auswirkung bei der Wiedergabe -- dort blieb die gesamte Wiedergabe an
|
||||
// genau dieser Stelle haengen). xterm.js' term.write() nimmt daher direkt
|
||||
// die rohen Bytes als Uint8Array entgegen -- xterm.js ist ein echter
|
||||
// Terminal-Emulator mit eigenem, chunk-uebergreifend korrektem
|
||||
// UTF-8-Parser, genau fuer diesen Fall gebaut.
|
||||
function b64decodeBytes(b64) {
|
||||
const bin = atob(b64);
|
||||
const bytes = new Uint8Array(bin.length);
|
||||
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Troubleshooting: der Server liefert bei einem Fehlschlag entweder eine
|
||||
@ -76,7 +92,7 @@
|
||||
ws.addEventListener("message", (ev) => {
|
||||
const msg = JSON.parse(ev.data);
|
||||
if (msg.type === "output") {
|
||||
term.write(b64decode(msg.data));
|
||||
term.write(b64decodeBytes(msg.data));
|
||||
} else if (msg.type === "error") {
|
||||
lastErrorMessage = msg.message;
|
||||
statusEl.textContent = "Fehler: " + msg.message;
|
||||
@ -107,6 +123,28 @@
|
||||
});
|
||||
document.addEventListener("fullscreenchange", sendResize);
|
||||
|
||||
document.getElementById("exit-btn").addEventListener("click", () => {
|
||||
// Sofortiges sichtbares Feedback, damit erkennbar ist, dass der Klick
|
||||
// ueberhaupt ankam -- unabhaengig davon, ob window.close() gleich
|
||||
// klappt oder der Fallback (siehe unten) erst nach der Wartezeit greift.
|
||||
statusEl.textContent = "Sitzung wird beendet ...";
|
||||
statusEl.classList.remove("error");
|
||||
try {
|
||||
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
|
||||
ws.close(1000, "Sitzung durch Benutzer beendet");
|
||||
}
|
||||
} catch (_) { /* bereits getrennt */ }
|
||||
window.close();
|
||||
// window.close() schliesst den Tab nur, wenn er per Skript/Link mit
|
||||
// target="_blank" geoeffnet wurde (siehe dashboard.js) UND noch keine
|
||||
// weitere Navigation darin stattfand -- sonst verweigern Browser das
|
||||
// lautlos, ohne Fehler oder Rueckgabewert. Deshalb IMMER zusaetzlich
|
||||
// nach kurzer Wartezeit zum Dashboard weiterleiten: war das Schliessen
|
||||
// erfolgreich, existiert die Seite dann laengst nicht mehr und der
|
||||
// Timeout laeuft ins Leere; sonst bleibt so ein Weg zurueck.
|
||||
window.setTimeout(() => { window.location.href = "/dashboard"; }, 300);
|
||||
});
|
||||
|
||||
// --- Dateitransfer-Panel ------------------------------------------------
|
||||
|
||||
const ftOverlay = document.getElementById("ft-overlay");
|
||||
@ -123,6 +161,11 @@
|
||||
}
|
||||
document.getElementById("filetransfer-btn").addEventListener("click", openFt);
|
||||
document.getElementById("ft-close-btn").addEventListener("click", closeFt);
|
||||
// Klick auf den abgedunkelten Hintergrund (nicht auf das Panel selbst)
|
||||
// schliesst das Overlay ebenfalls -- Standardverhalten fuer solche Panels.
|
||||
ftOverlay.addEventListener("click", (ev) => {
|
||||
if (ev.target === ftOverlay) closeFt();
|
||||
});
|
||||
|
||||
function formatSize(bytes) {
|
||||
if (bytes < 1024) return `${bytes} B`;
|
||||
|
||||
Reference in New Issue
Block a user