跳到主要内容

WebSocket Support

FluffOS supports WebSocket connections, letting modern web browsers connect directly to your mud without a separate telnet client. Players can reach the game from a web page, and the driver can serve the client itself.

Overview

FluffOS WebSocket support includes:

  • Multiple subprotocolstelnet, ascii, and binary
  • Secure WebSocket (WSS) — TLS-encrypted connections
  • Built-in web client — shipped in src/www
  • Full telnet protocol — option negotiation, GMCP, MSP, MXP, and more over the telnet subprotocol
  • Static file serving — serve the client's HTML/JS/CSS from the driver
  • Compressionpermessage-deflate when the client supports it

WebSocket Server Configuration

WebSocket listeners are configured like any other port, with the websocket protocol keyword. A WebSocket port additionally requires the websocket http dir option, which names the directory of static files to serve. See the driver configuration for the full port syntax.

Basic WebSocket Port

# Non-secure WebSocket
external_port_1 : websocket 8080

# Directory of static files (the web client)
websocket http dir : www

Secure WebSocket (WSS)

For production, enable TLS on the port with a matching external_port_N_tls line. The cert=/key= pair must be on a single line (the config parser reads each line whole and does not support backslash continuation).

external_port_1 : websocket 8443
external_port_1_tls : cert=etc/cert.pem key=etc/key.pem
websocket http dir : www

Multiple WebSocket Ports

# Regular telnet
port number : 4000

# Non-secure WebSocket (development)
external_port_1 : websocket 8080

# Secure WebSocket (production)
external_port_2 : websocket 8443
external_port_2_tls : cert=etc/cert.pem key=etc/key.pem

websocket http dir : www

Static Files Directory

websocket http dir is passed to the web server as-is, so a relative path is resolved from the driver's working directory (use an absolute path if that is ambiguous). It should contain an index.html plus any CSS, JavaScript, and images. FluffOS ships a full-featured client in src/www.

# Relative to the driver's working directory
websocket http dir : www

# Absolute path
websocket http dir : /var/www/mud

WebSocket Subprotocols

A browser selects a subprotocol as the second argument to new WebSocket(). FluffOS offers three:

telnet

The full telnet protocol over WebSocket — option negotiation plus the mud protocols listed below (GMCP, MSP, MXP, etc.). This is the subprotocol the built-in client uses.

const ws = new WebSocket('ws://mud.example.com:8080', ['telnet']);

ascii

Plain text with no telnet framing — lightweight, useful for simple clients and debugging.

const ws = new WebSocket('ws://mud.example.com:8080', ['ascii']);

binary

Handled identically to the telnet subprotocol; retained for compatibility with older clients.

const ws = new WebSocket('ws://mud.example.com:8080', ['binary']);

A WebSocket port also serves the static files from websocket http dir over plain HTTP, so browsing to http://host:port/ returns index.html (this is ordinary file serving, not a WebSocket connection).

Built-in Web Client

FluffOS ships a modern web client in src/www (index.html). It provides:

  • Connection management — configurable address/port, ws:// or wss://, and subprotocol selection
  • Full telnet handling — IAC commands, subnegotiation, option negotiation, GMCP, MSP, NAWS, terminal type
  • A terminal UI — ANSI color, command history, auto-scroll, and a responsive, mobile-friendly layout

Deploying the Web Client

Make the client available under your websocket http dir:

# Copy the client into place
cp -r src/www /path/to/mudlib/www

# Or symlink it
ln -s /path/to/fluffos/src/www /path/to/mudlib/www
websocket http dir : www
external_port_1 : websocket 8080

Then browse to http://localhost:8080/.

Customizing the Web Client

The client is a single index.html. Two useful entry points:

  • setDefaultConfig() sets the default address, port, and subprotocol.
  • processGMCPData(data) handles incoming GMCP messages — extend it to drive status bars, maps, or custom panels.
setDefaultConfig() {
this.protocolSelect.value = 'ws://';
this.addressInput.value = 'mud.yourdomain.com';
this.portInput.value = '8080';
this.subprotocolSelect.value = 'telnet';
}

GMCP Over WebSocket

Over the telnet subprotocol the client negotiates GMCP (Generic Mud Communication Protocol), so the standard GMCP efuns work unchanged.

Server-Side GMCP

send_gmcp() sends to the current interactive object, so call it from within the user's object (it takes a single string containing the package name followed by JSON). has_gmcp() reports whether a given interactive object negotiated GMCP (defaulting to the current object).

// Called in the context of the user object
if (has_gmcp()) {
send_gmcp("Char.Vitals { \"hp\": 100, \"mp\": 50, \"maxhp\": 100, \"maxmp\": 50 }");
send_gmcp("Room.Info { \"name\": \"Market Square\", \"area\": \"City\" }");
}

Client-Side GMCP

The web client parses GMCP messages and dispatches them through processGMCPData():

processGMCPData(data) {
switch (data.module) {
case 'Char.Vitals':
updateStatusBars(data.data);
break;
case 'Room.Info':
updateRoomDisplay(data.data);
break;
}
}

Telnet Protocol Over WebSocket

The telnet subprotocol supports the standard telnet options and the common mud protocols. Negotiation is handled by the driver's telnet layer, identically to a raw telnet connection.

Supported telnet options

  • ECHO (1) — echo control
  • SUPPRESS_GO_AHEAD (3)
  • TERMINAL_TYPE (24)
  • NAWS (31) — window size
  • NEW_ENVIRON (39) — environment variables
  • CHARSET (42) — character set negotiation

Supported mud protocols

  • MSDP (69) — Mud Server Data Protocol
  • MSSP (70) — Mud Server Status Protocol
  • MCCP2 (86) — Mud Client Compression Protocol
  • MSP (90) — Mud Sound Protocol
  • MXP (91) — Mud eXtension Protocol
  • ZMP (93) — Zenith Mud Protocol
  • GMCP (201) — Generic Mud Communication Protocol

The built-in client performs all negotiation automatically.

Security Considerations

Use WSS in Production

Always serve production traffic over WSS (see TLS Support):

external_port_1 : websocket 8443
external_port_1_tls : cert=/etc/letsencrypt/live/mud.example.com/fullchain.pem key=/etc/letsencrypt/live/mud.example.com/privkey.pem

Validating Player Input

Input from a WebSocket client arrives through the same path as any interactive connection — the normal command and input handling on the user object — not through receive_message (which is the apply for output sent to the user). Validate and rate-limit player input where you process commands, exactly as you would for a telnet connection; there is nothing WebSocket-specific to do.

Performance

Compression

FluffOS advertises permessage-deflate and uses it with any client that supports it, reducing bandwidth for large or repetitive output.

Troubleshooting

Connection fails: confirm the port is open through any firewall.

sudo ufw allow 8080/tcp
sudo ufw allow 8443/tcp

Static files 404: verify websocket http dir points at the directory that contains index.html.

websocket http dir : www

WSS certificate errors: use a certificate the client trusts (e.g. Let's Encrypt); see TLS Support.

GMCP not working: confirm the client negotiated it.

if (!has_gmcp(user)) {
write("Your client does not support GMCP.\n");
}

Enable WebSocket debug logging: the driver has a websocket debug category.

set_debug_level("websocket");

Testing WebSocket Connections

From a browser console:

const ws = new WebSocket('ws://localhost:8080', ['telnet']);
ws.onopen = () => console.log('Connected!');
ws.onmessage = (e) => console.log('Received:', e.data);
ws.send('look\n');

From the command line with wscat:

npm install -g wscat
wscat -c ws://localhost:8080 -s telnet

Reverse Proxying

You can place a WebSocket port behind a web server, for example to serve the mud client alongside a website or to terminate TLS at the proxy:

server {
listen 80;
server_name mud.example.com;

location / {
proxy_pass http://webapp:3000;
}

location /ws {
proxy_pass http://fluffos:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}

See Also

References