Implement own client using ttyd only on server side
Is there a way to implement ttyd's client side in my own application? I mean, implement xterm.js in my own application that connects to the websocket provided by ttyd? What would the vanilla js code look like?
If this is technically possible, I would really like to sponsor this project. Please let me know what you think.
Sure, as long as you implement ttyd's websocket protocol, it's pretty simple.
https://github.com/tsl0922/ttyd/blob/40e79c706be14029b391f369bee6613c31667abb/html/src/components/terminal/xterm/index.ts#L25-L36
Glad to hear that, thanks. If you like, I would like to sponsor a fully working vanilla javascript example. Would you be open to such an offer? I mean, I'm not a javascript pro and you know how to do it... I would like to sponsor an example index.html with vanilla js showing how an external page could connect to the ttyd socket. If you like, you can include this example here in the project, or anywhere, as open source code. Others might be interested in it too. If you are interested, let me know how I can contact you privately to talk about sponsoring...
Why not just copy the code in this project?
If you really want a vanilla javascript example, I would recommend you to take a look at xterm.js's demo: https://github.com/xtermjs/xterm.js/tree/master/demo
Sure, as long as you implement ttyd's websocket protocol, it's pretty simple.
ttyd/html/src/components/terminal/xterm/index.ts
Lines 25 to 36 in 40e79c7
enum Command { // server side OUTPUT = '0', SET_WINDOW_TITLE = '1', SET_PREFERENCES = '2', // client side INPUT = '0', RESIZE_TERMINAL = '1', PAUSE = '2', RESUME = '3', }
There is a working example of that? I tried to implement ttyd's protocol but coud not get it working:
const WebSocket = require('ws');
const ws = new WebSocket("ws://127.0.0.1:8003");
ws.binaryType = "arraybuffer"; // Expect binary data
ws.onopen = () => {
console.log("✅ Connected to ttyd!");
setTimeout(() => {
if (ws.readyState === WebSocket.OPEN) {
console.log("📤 Sending command: ls");
ws.send(new Uint8Array([0x00, ...new TextEncoder().encode("ls\n")]));
} else {
console.warn("⚠️ WebSocket not open. Cannot send data.");
}
}, 500); // Wait a little before sending
};
ws.onmessage = (event) => {
console.log("📥 Raw Data Received:", event.data); // Debug raw data
const data = new Uint8Array(event.data);
if (data.length === 0) {
console.warn("⚠️ Received empty message!");
return;
}
const type = data[0]; // Extract message type
console.log("📥 Message Type:", type);
switch (type) {
case 0x01: // Terminal output
console.log("📥 Terminal Output:\n" + new TextDecoder().decode(data.slice(1)));
break;
case 0x05: // Window title change
console.log("🖥️ Window Title Changed:", new TextDecoder().decode(data.slice(1)));
break;
default:
console.warn("⚠️ Unknown message type:", type);
}
};
ws.onerror = (error) => {
console.error("❌ WebSocket Error:", error);
};
ws.onclose = (event) => {
console.log(`🔌 Connection closed (Code: ${event.code}, Reason: ${event.reason})`);
};
const ws = new WebSocket("ws://127.0.0.1:8003", ["tty"]);
I debugged for a long time and found that the protocol must be set to tty.