|
| 1 | +# Foxglove Studio WebSocket protocol v1 |
| 2 | + |
| 3 | +## Protocol overview |
| 4 | + |
| 5 | +- An application wishing to provide data for streamed consumption by Foxglove Studio hosts a [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) server. |
| 6 | + |
| 7 | +- The client (Foxglove Studio) will specify supported subprotocols (a standard part of the WebSocket handshake) when establishing the connection. The current version of this document corresponds to subprotocol `foxglove.websocket.v1`. The server must select a subprotocol with which it is compatible for the connection to continue. |
| 8 | + |
| 9 | + - Example client code in JavaScript: |
| 10 | + ```js |
| 11 | + new WebSocket("ws://...", ["foxglove.websocket.v1"]); |
| 12 | + ``` |
| 13 | + |
| 14 | +- Both text and binary messages are used on the WebSocket connection. |
| 15 | + |
| 16 | + - Each text message must be a JSON object having a field called `op` which identifies the type of message. The interpretation of the other fields depends on the opcode. |
| 17 | + |
| 18 | + - Similarly, each binary message starts with a 1-byte opcode identifying the type of message. The interpretation of the remaining bytes depends on the opcode. |
| 19 | + |
| 20 | +- Upon establishing a connection, the server must send clients a Server Info message with a list of supported capabilities. |
| 21 | + |
| 22 | +## Summary of messages |
| 23 | + |
| 24 | +### Sent by server |
| 25 | + |
| 26 | +- [Server Info](#server-info) (json) |
| 27 | +- [Status](#status) (json) |
| 28 | +- [Advertise](#advertise) (json) |
| 29 | +- [Unadvertise](#unadvertise) (json) |
| 30 | +- [Message Data](#message-data) (binary) |
| 31 | + |
| 32 | +### Sent by client |
| 33 | + |
| 34 | +- [Subscribe](#subscribe) (json) |
| 35 | +- [Unsubscribe](#unsubscribe) (json) |
| 36 | + |
| 37 | +## JSON messages |
| 38 | + |
| 39 | +Each JSON message must be an object containing a field called `op` which identifies the type of message. |
| 40 | + |
| 41 | +### Server Info |
| 42 | + |
| 43 | +- This message is always sent to new clients upon connection. |
| 44 | + |
| 45 | +#### Fields |
| 46 | + |
| 47 | +- `op`: string `"serverInfo"` |
| 48 | +- `name`: free-form information about the server which the client may optionally display or use for debugging purposes |
| 49 | +- `capabilities`: array of strings (reserved for future expansions to the spec) |
| 50 | + |
| 51 | +#### Example |
| 52 | + |
| 53 | +```json |
| 54 | +{ |
| 55 | + "op": "serverInfo", |
| 56 | + "name": "example server", |
| 57 | + "capabilities": [] |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +### Status |
| 62 | + |
| 63 | +- The server may send this message at any time. Client developers may use it for debugging purposes, display it to the end user, or ignore it. |
| 64 | + |
| 65 | +#### Fields |
| 66 | + |
| 67 | +- `op`: string `"status"` |
| 68 | +- `level`: 0 (info), 1 (warning), 2 (error) |
| 69 | +- `message`: string |
| 70 | + |
| 71 | +#### Example |
| 72 | + |
| 73 | +```json |
| 74 | +{ |
| 75 | + "op": "status", |
| 76 | + "level": 0, |
| 77 | + "message": "Some info" |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +### Advertise |
| 82 | + |
| 83 | +- Informs the client about newly available channels. |
| 84 | +- At least one Advertise message is always sent to new clients upon connection. |
| 85 | + |
| 86 | +#### Fields |
| 87 | + |
| 88 | +- `op`: string `"advertise"` |
| 89 | +- `channels`: array of: |
| 90 | + - `id`: number. The server may reuse ids when channels disappear and reappear, but only if the channel keeps the exact same topic, encoding, schemaName, and schema. Clients will use this unique id to cache schema info and deserialization routines. |
| 91 | + - `topic`: string |
| 92 | + - `encoding`: string |
| 93 | + - `schemaName`: string |
| 94 | + - `schema`: string |
| 95 | + |
| 96 | +#### Example |
| 97 | + |
| 98 | +```json |
| 99 | +{ |
| 100 | + "op": "advertise", |
| 101 | + "channels": [ |
| 102 | + { |
| 103 | + "id": 1, |
| 104 | + "topic": "foo", |
| 105 | + "encoding": "protobuf", |
| 106 | + "schemaName": "ExampleMsg", |
| 107 | + "schema": "ZXhhbXBsZSBkYXRh" |
| 108 | + } |
| 109 | + ] |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +### Unadvertise |
| 114 | + |
| 115 | +Informs the client that channels are no longer available. |
| 116 | + |
| 117 | +#### Fields |
| 118 | + |
| 119 | +- `op`: string `"unadvertise"` |
| 120 | +- `channelIds`: array of number, corresponding to previous Advertise |
| 121 | + |
| 122 | +#### Example |
| 123 | + |
| 124 | +```json |
| 125 | +{ |
| 126 | + "op": "unadvertise", |
| 127 | + "channelIds": [1, 2] |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +### Subscribe |
| 132 | + |
| 133 | +- Requests that the server start streaming messages on a given topic (or topics) to the client. |
| 134 | +- A client may only have one subscription for each channel at a time. |
| 135 | + |
| 136 | +#### Fields |
| 137 | + |
| 138 | +- `op`: string `"subscribe"` |
| 139 | +- `subscriptions`: array of: |
| 140 | + - `id`: number chosen by the client. The client may not reuse ids across multiple active subscriptions. The server may ignore subscriptions that attempt to reuse an id (and send an error status message). After unsubscribing, the client may reuse the id. |
| 141 | + - `channelId`: number, corresponding to previous Advertise message(s) |
| 142 | + |
| 143 | +#### Example |
| 144 | + |
| 145 | +```json |
| 146 | +{ |
| 147 | + "op": "subscribe", |
| 148 | + "subscriptions": [ |
| 149 | + { "id": 0, "channelId": 3 }, |
| 150 | + { "id": 1, "channelId": 5 } |
| 151 | + ] |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | +### Unsubscribe |
| 156 | + |
| 157 | +- Requests that the server stop streaming messages to which the client previously subscribed. |
| 158 | + |
| 159 | +#### Fields |
| 160 | + |
| 161 | +- `op`: string `"subscribe"` |
| 162 | +- `subscriptionIds`: array of number, corresponding to previous Subscribe message(s) |
| 163 | + |
| 164 | +#### Example |
| 165 | + |
| 166 | +```json |
| 167 | +{ |
| 168 | + "op": "unsubscribe", |
| 169 | + "subscriptionIds": [0, 1] |
| 170 | +} |
| 171 | +``` |
| 172 | + |
| 173 | +## Binary messages |
| 174 | + |
| 175 | +All binary messages must start with a 1-byte opcode identifying the type of message. The interpretation of the remaining bytes depends on the opcode. |
| 176 | + |
| 177 | +All integer types explicitly specified (uint32, uint64, etc.) in this section are encoded with **little-endian** byte order. |
| 178 | + |
| 179 | +### Message Data |
| 180 | + |
| 181 | +- Provides a raw message payload, encoded as specified in the Advertise corresponding to the channel. |
| 182 | +- Subscription id must correspond to a Subscribe that was previously sent. |
| 183 | + |
| 184 | +| Bytes | Type | Description | |
| 185 | +| --------------- | ------- | ------------------------------- | |
| 186 | +| 1 | opcode | 0x01 | |
| 187 | +| 4 | uint32 | subscription id | |
| 188 | +| 8 | uint64 | receive timestamp (nanoseconds) | |
| 189 | +| remaining bytes | uint8[] | message payload | |
0 commit comments