ReStream delivers events over a single WebSocket endpoint. Clients must connect, subscribe to channels, and decode the incoming Protocol Buffer payloads.
Production endpoint: wss://restream.bags.fm
This is a more complex guide on how to connect to ReStream manually, ideally, for most use cases, using the SDK is easier and more practical. You can read more about how to connect using the SDK here.
Each event is serialized with the following structure:
{topic}:{subject};{varint_len}{protobuf_payload}
- topic: The event type (e.g. launchpad_launch)
- subject: The subject of the event (e.g. BAGS)
- ;: A delimiter separating the channel from the payload
- varint_len: Length of the protobuf payload, encoded as a varint
- You can read more about delimited protobuf events here.
- protobuf_payload: The actual event, encoded as a Protocol Buffer message
Head to #supported-events for more details on topics and subjects.
You must parse the prefix topic:subject;
before decoding the protobuf payload.
Connecting
Before you can subscribe to events, you need to establish a WebSocket connection to the ReStream endpoint.
Prerequisites
npm install ws protobufjs
Establishing connection
import WebSocket from "ws";
const ws = new WebSocket("wss://restream.bags.fm");
ws.on("open", () => {
console.log("Connected to ReStream");
// Start ping task - Check next chapter for infos
// startPingTask(ws);
// Subscribe to a launchpad channel
ws.send(
JSON.stringify({
type: "subscribe",
event: "launchpad_launch:BAGS",
})
);
});
Decoding events
import { Reader } from "protobufjs/minimal";
import { LaunchpadLaunchEvent } from "./gen/restream_events";
/**
* Decode a LaunchpadLaunchEvent from a serialized buffer.
*
* Buffer format:
* [topic][":" delimiter][subject][";" suffix][varint length][protobuf payload]
*/
export function decodeLaunchpadLaunchEvent(
buf: Uint8Array
): LaunchpadLaunchEvent {
// 1. Find the SUFFIX marker (`;`)
const suffixByte = ";".charCodeAt(0);
let suffixIndex = -1;
for (let i = 0; i < buf.length; i++) {
if (buf[i] === suffixByte) {
suffixIndex = i;
break;
}
}
if (suffixIndex === -1) {
throw new Error("Invalid buffer: SUFFIX ';' not found");
}
// 2. Slice after SUFFIX
const afterSuffix = buf.subarray(suffixIndex + 1);
// 3. Decode using protobufjs's decodeDelimited
return LaunchpadLaunchEvent.decodeDelimited(afterSuffix);
}
Connection Requirements
Clients must send a ping
message at least once every minute to keep their connection alive. Connections that don’t ping within 60 seconds will be automatically disconnected.
It’s recommended to set up a ping interval:
// Send ping every 30 seconds to ensure connection stays alive
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);