Terminal Streaming example in Javascript
Stream a TUI application over websockets using xterm.js.
➡ View demo online (not mobile-friendly)
➡ View full source on GitHub
➡ Run the example
Running the example
You can run this self-contained example using Docker.
git clone https://github.com/scalesocket/scalesocket
cd scalesocket/examples/
docker compose up --build terminal
Then open http://localhost:5000/
in your browser.
Frontend code
The frontend is a single html file, index.html
, using xterm.js. It connects with websockets to the server and shows a chat interface.
The javascript defines the terminal windget and connects it to a websocket:
const $ = document.querySelector.bind(document);
const protocol = window.location.protocol === "https:" ? "wss" : "ws";
const params = new URLSearchParams(document.location.search);
const room = params.get("room") ?? 'default';
// create a terminal
const term = new Terminal({ disableStdin: false });
const element = $('#terminal');
// connect to websocket server and room based on URL
const ws = new WebSocket(`${protocol}:${window.location.host}/${room}`);
const attachAddon = new AttachAddon.AttachAddon(ws);
// attach the socket to term
term.loadAddon(attachAddon);
term.open(element);
ws.addEventListener("open", (event) => {
$('.xterm-helper-textarea').focus();
// some magic escape sequence to make input work for late-joiners
term.write('\x1b)0\x1b7\x1b[?47h\x1b[1;24r\x1b[m\x1b[4l\x1b[?1h\x1b=');
});
Backend code
There is no backend code, besides running a terminal application. The backend in this example is a wrapped snake process.
Backend server
The backend is the ScaleSocket server.
We want to:
- let participants join rooms based on URL
- start a new
snake
process when a new user connects - host a static html file
To do this, start ScaleSocket using:
scalesocket --addr 0.0.0.0:5000\
--binary\
--staticdir /var/www/public/\
# launch using unbuffer to expose a pty
bash -- -c 'TERM=xterm-color unbuffer -p nsnake'
Note that we are using the --binary
flag to enable binary mode. Furthermore, unbuffer(1) and TERM
let snake work as-if it was run in an interactive terminal.
How does it work?
The frontend connects to the server using websockets. The backend spins up a new snake
process.
When the frontend terminal widget sends a key-press, ScaleSocket passes it directly to the stdin of snake
.
Since snake
writes the screen to the terminal using stdout, ScaleSocket forwards it back to all connected clients.
Was this page helpful?