Files
NanoKVM-MIRROR/web/src/pages/terminal/xterm.tsx
2024-08-27 15:40:42 +08:00

81 lines
2.1 KiB
TypeScript

import { useEffect } from 'react';
import { AttachAddon } from '@xterm/addon-attach';
import { FitAddon } from '@xterm/addon-fit';
import { Terminal as XtermTerminal } from '@xterm/xterm';
import '@xterm/xterm/css/xterm.css';
import { getBaseUrl } from '@/lib/service.ts';
type TerminalProps = {
token: string;
setToken: (token: string) => void;
};
export const Xterm = ({ token, setToken }: TerminalProps) => {
useEffect(() => {
const terminalEle = document.getElementById('terminal');
if (!terminalEle) return;
const terminal = new XtermTerminal();
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
terminal.open(terminalEle);
fitAddon.fit();
const url = `${getBaseUrl('ws')}/api/vm/terminal?${token}`;
const webSocket = new WebSocket(url);
const sendSize = () => {
const windowSize = { high: terminal.rows, width: terminal.cols };
const blob = new Blob([JSON.stringify(windowSize)], { type: 'application/json' });
webSocket.send(blob);
};
const resizeScreen = () => {
fitAddon.fit();
sendSize();
};
window.addEventListener('resize', resizeScreen, false);
const attachAddon = new AttachAddon(webSocket);
terminal.loadAddon(attachAddon);
webSocket.onopen = () => {
sendSize();
setTimeout(runPicocom, 300);
};
webSocket.onerror = () => {
setToken('');
};
webSocket.onclose = () => {
setToken('');
};
const runPicocom = () => {
const urls = window.location.href.split('?');
if (urls.length < 2) return;
const searchParams = new URLSearchParams(urls[1]);
const port = searchParams.get('port');
const baud = searchParams.get('baud');
if (!port || !baud) return;
webSocket.send(`picocom ${port} -b ${baud}\r`);
};
return () => {
window.removeEventListener('resize', resizeScreen, false);
if (webSocket.readyState === 1) {
webSocket.close();
}
};
}, []);
return (
<div className="h-full w-full overflow-hidden">
<div id="terminal" className="h-full p-2"></div>
</div>
);
};