WebSocket Transport
This document specifies how to send and receive Fusain packets over WebSocket connections.
Overview
WebSocket provides a reliable, bidirectional transport layer for Fusain communication between web applications and Fusain-enabled devices or gateways.
Use Cases:
Browser-based controller applications
Mobile web apps for device monitoring
Remote access through WebSocket gateways
Transport Format
Fusain packets are transmitted as binary WebSocket frames.
Frame Type
All Fusain messages MUST be sent as binary frames (opcode 0x02), not text
frames.
websocket.binaryType = 'arraybuffer';
Packet Encoding
Fusain packets are transmitted in their complete wire format, including:
START delimiter (
0x7E)Byte-stuffed content (LENGTH, ADDRESS, MSG_TYPE, PAYLOAD, CRC)
END delimiter (
0x7F)
This preserves compatibility with serial transport and allows the same encoding/decoding logic to be used across all transports.
Message Boundaries
Each WebSocket binary frame contains exactly one complete Fusain packet. Unlike serial transport, WebSocket frame boundaries define packet boundaries.
Implementations SHOULD still validate the START and END delimiters to detect malformed packets.
Connection Handling
Session Initiation
After WebSocket connection is established:
Client sends DISCOVERY_REQUEST to initiate session
Gateway responds with DEVICE_ANNOUNCE for each accessible appliance
Begin normal Fusain communication
For session initiation details, see Session Initiation in Packet Routing.
Authentication
For appliance filtering based on client identity, gateways MAY use:
Client certificates: Subject DN or certificate fingerprint (preferred)
Authorization header: Bearer token or other credential
When client certificates are not used, include credentials in the WebSocket handshake:
GET /fusain HTTP/1.1
Host: gateway.example.com
Upgrade: websocket
Connection: Upgrade
Authorization: Bearer <token>
The gateway validates credentials during the HTTP upgrade and associates the authenticated identity with the WebSocket connection for appliance filtering.
Heartbeat
Clients SHOULD send PING_REQUEST packets periodically to:
Maintain router subscription timeouts (routers remove subscriptions after 60 seconds without PING_REQUEST)
Maintain the connection through proxies and firewalls
Detect connection failures
RECOMMENDED interval: 10-15 seconds.
Note
Client PING_REQUEST maintains router subscription timeouts only. Routers handle appliance communication timeouts independently. See Packet Routing for details on ping behavior in routed topologies.
Reconnection
Clients SHOULD implement automatic reconnection with exponential backoff.
Packet Encoding
The following JavaScript implementations correspond to the algorithms specified in Packet Format.
CRC-16-CCITT
See CRC Calculation for algorithm parameters.
function crc16ccitt(data) {
let crc = 0xFFFF;
for (const byte of data) {
crc ^= byte << 8;
for (let i = 0; i < 8; i++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021;
} else {
crc = crc << 1;
}
}
crc &= 0xFFFF;
}
return crc;
}
Byte Stuffing
See Byte Stuffing for escape sequences.
const START = 0x7E;
const END = 0x7F;
const ESC = 0x7D;
function byteStuff(data) {
const result = [];
for (const byte of data) {
if (byte === START) {
result.push(ESC, 0x5E);
} else if (byte === END) {
result.push(ESC, 0x5F);
} else if (byte === ESC) {
result.push(ESC, 0x5D);
} else {
result.push(byte);
}
}
return new Uint8Array(result);
}
function byteUnstuff(data) {
const result = [];
let i = 0;
while (i < data.length) {
if (data[i] === ESC && i + 1 < data.length) {
result.push(data[i + 1] ^ 0x20);
i += 2;
} else {
result.push(data[i]);
i += 1;
}
}
return new Uint8Array(result);
}
Gateway Implementation
Server Requirements
WebSocket gateways that bridge to serial Fusain devices MUST:
Accept binary WebSocket frames only
Forward complete Fusain packets without modification
Handle multiple concurrent WebSocket clients
Implement connection-based routing (see Packet Routing)
Packet Forwarding
The gateway acts as a transparent bridge:
WebSocket Client Gateway Serial Device
| | |
|-- Binary Frame (packet) -->| |
| |-- Serial bytes --------->|
| | |
| |<-- Serial bytes ---------|
|<-- Binary Frame (packet) --| |
Multi-Client Support
When multiple WebSocket clients connect to the same gateway:
Command packets from any client are forwarded to the serial bus
Data packets from appliances are forwarded only to clients that have subscribed via DATA_SUBSCRIPTION (see Packet Routing)
Clients MUST send DATA_SUBSCRIPTION to receive telemetry from specific appliances
Error Handling
Decode Errors
When a packet fails to decode (CRC error, invalid format):
Log the error for debugging
Discard the packet
Do NOT send an error response over WebSocket
ws.onmessage = (event) => {
try {
const packet = decodePacket(new Uint8Array(event.data));
handlePacket(packet);
} catch (error) {
console.warn('Ignoring malformed packet:', error.message);
}
};
Connection Errors
Handle WebSocket errors gracefully:
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
ws.onclose = (event) => {
if (!event.wasClean) {
console.warn('Connection lost, reconnecting...');
scheduleReconnect();
}
};