diff options
author | Toby Vincent <tobyv13@gmail.com> | 2022-03-23 23:56:09 -0500 |
---|---|---|
committer | Toby Vincent <tobyv13@gmail.com> | 2022-03-23 23:56:09 -0500 |
commit | 2a4cf89020f7baf2ef22d150b3afc24eba7df9cc (patch) | |
tree | f4485ca2beb16c5bd98bfb4995503635d4aa1290 /src | |
parent | 524f617050c1ed0495ac04b9c0dc00e50e30ee11 (diff) |
feat: implement pty over websocket
Diffstat (limited to 'src')
-rw-r--r-- | src/App.js | 76 |
1 files changed, 41 insertions, 35 deletions
@@ -4,14 +4,20 @@ import { Terminal } from 'xterm'; import './xterm.css'; import { FitAddon } from 'xterm-addon-fit'; import React from 'react'; +import { Resizable } from "re-resizable"; +import ResizeObserver from "react-resize-observer"; export default class App extends React.Component { constructor(props) { super(props); + this.fitAddon = new FitAddon(); this.term = new Terminal({ + screenKeys: true, + useStyle: true, cursorBlink: true, fontSize: 18, fontWeight: 900, + fontFamily: `'Fira Mono', monospace`, theme: { foreground: "#fff", background: "#000", @@ -29,7 +35,10 @@ export default class App extends React.Component { this.socket = new WebSocket('ws://localhost:8000/ws'); this.socket.binaryType = 'arraybuffer'; - this.fitAddon = new FitAddon(); + function ab2str(buf) { + return String.fromCharCode.apply(null, new Uint8Array(buf)); + } + // this.attachAddon = new AttachAddon(this.socket, false); this.term.loadAddon(this.fitAddon); @@ -38,49 +47,41 @@ export default class App extends React.Component { this.term.open(document.getElementById("xterm")); this.fitAddon.fit(); - const recvData = data => { - var type = "text"; - - if (typeof data !== 'string') { - data = this.decoder.decode(data); - var type = "binary"; - } + // Terminal events + this.term.onData((data) => { + this.socket.send(this.encoder.encode("\x00" + data)); + }); - console.log(`Received ${type}: ${data}`); - this.term.write(data); - } + this.term.onResize((evt) => { + this.socket.send(this.encoder.encode("\x01" + JSON.stringify({ cols: evt.cols, rows: evt.rows }))) + }); - const sendData = (data, isBinary) => { - var type = "text"; + this.term.onTitleChange((title) => { + document.title = title; + }); - if (isBinary) { - data = this.encoder.encode(data); - var type = "binary"; + // Socket events + this.socket.onmessage = (evt) => { + if (evt.data instanceof ArrayBuffer) { + this.term.write(ab2str(evt.data.slice(1))); + } else { + alert(evt.data) } - - console.log(`Sending ${type}: ${data}`); - this.socket.send(data); + } + this.socket.onclose = (evt) => { + this.term.write("Session terminated"); + this.term.destroy(); } - this.socket.onmessage = e => recvData(e.data); - this.term.onKey(Key => { - switch (Key.domEvent.key) { - case "Enter": - sendData('\n'); - break; - - default: - sendData(Key.key); - break; + this.socket.onerror = (evt) => { + if (typeof console.log == "function") { + console.log(evt) } + } - }); + this.fitAddon.fit(); } - linefeed = () => { - var shellprompt = "$ "; - this.term.write("\r\n" + shellprompt); - }; render() { return ( @@ -91,7 +92,12 @@ export default class App extends React.Component { Edit <code>src/App.js</code> and save to reload. </p> <div className="terminalContainer"> - <div id="xterm"></div> + <div id="xterm" style={{ height: "100%", width: "100%" }} /> + <ResizeObserver + onResize={() => { + this.fitAddon.fit(); + }} + /> </div> </header> </div> |