Skip to content

Multiplexed WebSocket Streams

Adam Magaluk edited this page Jul 26, 2016 · 8 revisions

Zetta uses a simple WebSocket sub-protocol for subscribing to multiple streams over one socket. This feature also allows advanced filtering.

Zetta exposes a link on the root resource of the Client API.

{
  "rel": ["http://rels.zettajs.io/events"],
  "href": "ws://example.com/events"
}

After a client’s initial connection, no streams will be subscribed to implicitly. Subscription requests must be sent over the WebSocket. Then event messages will be received.

There is an optional query parameter that can be set filterMultiple that when set to true will only return unique messages to a client once regardless of the number of subscriptions that match the topic. When receiving the Event Message subscriptionId becomes an array of subscription ids that are fulfilled for that message.

The pattern for topic names can be derived from information about a server, a device, and a stream:

{server-name}/{device-type}/{device-id}/{stream-name}

For a CaQL device query the format for the topic is:

{server-name}/query/{CaQL query}

Subscription Request

A client SHOULD send only one Subscription Request per topic. Upon a successful request, the server MUST send a Subscription Acknowledgement Message. If an error is encountered processing the request, the server MUST send an Error Message if it's able. After a Subscription Acknowledgement Message, a client will start receiving Event Messages.

A subscription request MUST contain the following properties:

  • type - Must be set to the string "subscribe". (String)
  • topic - The topic of the subscription. See Topic Format below for more information. (String)

Optionally, a subscription request MAY contain the following properties:

  • limit - Number of events to be received before the client is automatically unsubscribed from the topic. Server will send an unsubscribe-ack when the limit is reached. When not present, a value of Infinity will be used. (Number)

Topic Format

For a Subscription Request, the topic provided is hierarchical, with each node separated by a slash (/), such as:

Detroit/thermostat/a5cb1a72-c3e7-47b6-818d-6d81b16e9ed4/temperature

Wildcard Support

Topics may include wildcards. A wildcard is represented by an asterisk (*) and may be used in hierarchical topics, such as:

Detroit/thermostat/*/temperature

A single asterisk (*) denotes a wildcard for a single level of the hierarchy. A double asterisk (**) denotes a wildcard for multiple levels of the hierarchy, such as:

Detroit/**/temperature

Regular Expression Support

Topic nodes may be represented in the form of a regular expression. Regular expressions should be wrapped in curly braces ({}), such as:

{^Det.+$}/thermostat/a5cb1a72-c3e7-47b6-818d-6d81b16e9ed4/temperature.

Query Support

Topics may also include a query. Queries ensure an event is only published if it meets a certain filter. They also allow for field selection. Queries are expressed in the Calypso Query Language. They are appended to a topic after a question mark, such as:

Detroit/thermostat/*/temperature?select * where data > 85

Detroit/thermostat/*/temperature?select data.degreesC where data.degreesF > 85

Example

{
  "type": "subscribe",
  "topic": "Detroit/arm/a5cb1a72-c3e7-47b6-818d-6d81b16e9ed4/state",
  "limit": 10
}

Subscription Acknowledgement Message

A server MUST send a Subscription Acknowledgement Message to a client upon a successful subscription.

A Subscription Acknowledgement Message MUST contain the following properties:

  • type - Must be set to the string "subscribe-ack". (String)
  • timestamp - A UTC timestamp of when the message was sent. (Number)
  • topic - The topic of the subscription. (String)
  • subscriptionId - Subscription identifier to be returned with related Event Messages. (Number)

Example

{
  "type": "subscribe-ack",
  "timestamp": 1442944840135,
  "topic": "Detroit/arm/a5cb1a72-c3e7-47b6-818d-6d81b16e9ed4/state",
  "subscriptionId": 2
}

Event Message

Once a subscription request has been made, an Event Message stream will start to flow.

An Event Message MUST contain the following properties:

  • type - Must be set to the string "event". (String)
  • topic - The topic to which the message belongs. (String)
  • subscriptionId - Identifier of the associated subscription. (Number)
  • timestamp - A UTC timestamp of when the message was sent. (Number)
  • data - The data payload for the message. (String|Number|Array|Object)

TODO: Add language about queries coming back as an object (key-value pairs).

Example

{
  "type": "event",
  "topic": "Detroit/arm/a5cb1a72-c3e7-47b6-818d-6d81b16e9ed4/state",
  "subscriptionId": 2,
  "timestamp": 1442944840135,
  "data": "moving-claw"
}

Unsubscribe Request

Once an Unsubscribe Request is received, the server MUST perform a best effort to stop the message flow immediately. The client MAY receive additional messages for a topic while the server is processing the request. Upon successfully processing an Unsubscribe Request, a server MUST send an Unsubscribe Acknowledgement Message. If an error is encountered processing the request, the server should send an Error Message.

An Unsubscribe Request MUST contain the following properties:

  • type - Must be set to the string "unsubscribe". (String)
  • subscriptionId - The identifier of the subscription. (Number)

Example

{
  "type": "unsubscribe",
  "subscriptionId": 2
}

Unsubscribe Acknowledgement Message

A server MUST send an Unsubscribe Acknowledgement Message to a client upon successfully processing an Unsubscribe Request.

An Unsubscribe Acknowledgement Message MUST contain the following properties:

  • type - Must be set to the string "unsubscribe-ack". (String)
  • timestamp - A UTC timestamp of when the message was sent. (Number)
  • subscriptionId - The identifier of the subscription. (Number)

Example

{
  "type": "unsubscribe-ack",
  "timestamp": 1442944840135,
  "subscriptionId": 2
}

Error Message

A server MUST send an Error Message upon encountering any issues processing requests from clients.

An Error Message MUST contain the following properties:

  • type - Must be set to the string "error". (String)
  • code - Error code defining the error. See Error Codes below. (Number)
  • timestamp - A UTC timestamp of when the message was sent. (Number)
  • topic - The topic of the subscription. (String)

An Error Message MAY contain the following property:

  • message - A plaintext description of the error. (String)
  • subscriptionId - Identifier of the associated subscription. Only applicable if an error occurs after a subscription is established. (Number)

Error Codes

  • 400 - Bad Request - Invalid JSON in request
  • 405 - Method Not Supported - Invalid "type" value for incoming message.
  • 500 - Server Error - We messed up.

Example

{
  "type": "error",
  "code": 500,
  "timestamp": 1442944840135,
  "topic": "Detroit/arm/a5cb1a72-c3e7-47b6-818d-6d81b16e9ed4/state",
  "message": "Server exploded.",
  "subscriptionId": 2
}

Ping Request

Upon receipt of a Ping request, the server MUST send a Pong message in response. The server SHOULD respond with Pong frame as soon as is practical.

A server MAY send a Ping request to the client any time after the connection is established and before the connection is closed.

NOTE: A Ping frame may serve either as a keepalive or as a means to verify that the remote endpoint is still responsive.

A Ping request MUST contain the following properties:

  • type - Must be set to the string "ping". (String)

Optionally, a Ping request MAY contain the following properties:

  • data - Optional “Application data”, will be returned in the Pong response. (String)

Example

{
  "type": "ping",
  "data": "Optional data"
}

Pong Message

A Pong message is sent in response to a Ping request and MUST have identical "Application data" as found in the “data” field of the Ping request being replied to.

A Pong Message MUST contain the following properties:

  • type - Must be set to the string "pong". (String)
  • timestamp - A UTC timestamp of when the message was sent. (Number)

Optionally, a Pong Message MAY contain the following properties:

  • data - “Application data”, if present in the Ping request being replied to. (String)

Example

{
  "type": "pong",
  "timestamp": 1442944840135,
  "data": "Optional data"
}
Clone this wiki locally