CluPilotCloud/resources/js/terminal.js

55 lines
1.7 KiB
JavaScript

/*
* Das Terminal im eigenen Fenster.
*
* Eigener Einstiegspunkt, nicht Teil von app.js: diese Seite lädt weder
* Livewire noch Chart.js, und app.js zöge beides mit — auf einer Seite, die
* eine WebSocket-Verbindung und ein Terminal ist, sonst nichts.
*/
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import '@xterm/xterm/css/xterm.css'
const root = document.querySelector('[data-terminal]')
if (root) {
const splash = root.querySelector('[data-terminal-splash]')
const screen = root.querySelector('[data-terminal-screen]')
const term = new Terminal({ convertEol: true, fontFamily: 'ui-monospace, monospace', fontSize: 13 })
const fit = new FitAddon()
term.loadAddon(fit)
const scheme = location.protocol === 'https:' ? 'wss' : 'ws'
const socket = new WebSocket(`${scheme}://${location.host}/terminal/ws?t=${encodeURIComponent(root.dataset.ticket)}`)
socket.binaryType = 'arraybuffer'
// Der Vorspann weicht beim ERSTEN BYTE, nicht bei `onopen`.
let opened = false
const reveal = () => {
if (opened) return
opened = true
splash.classList.add('hidden')
screen.classList.remove('hidden')
term.open(screen)
fit.fit()
}
socket.onmessage = (event) => {
reveal()
term.write(new Uint8Array(event.data))
}
term.onData((data) => socket.readyState === WebSocket.OPEN && socket.send(data))
socket.onclose = () => {
reveal()
term.write('\r\n\x1b[31m— Verbindung beendet —\x1b[0m\r\n')
}
socket.onerror = () => {
reveal()
term.write('\r\n\x1b[31m— Verbindung nicht möglich —\x1b[0m\r\n')
}
addEventListener('resize', () => opened && fit.fit())
}