Subscriber Protocols

Subscribers are invoked by a topic when an event is sent to that topic. You can find all currently supported subscriber protocols below.

Subscriber Commonalities

Common Flags

  • Volatile: The subscription will be removed upon any failure to send to it.
  • Retry: The subscription will retry automatically (backing off) for 3 days. At a rate of 2^n * 15 where n is number of attempts. Incompatible with volatile.

Url Templating

You can use handlebars-style string templating for your subscription URL to populate it with items from the payload. Any population will be URL-Encoded. (It actually uses lodash.get under-the-hood. You can use any format supported by it.)

For example, if you receive an event with the data:

{"name": "test", b: {"val" : 123}}

you might have a subscriber URL that uses the field name in it:

http://example.com/event?eventName={{name}}&nested={{b.val}}

HTTP/HTTPS

The event will be sent over normal http/https, with the method of your choosing.

Any HTTP method is supported. There is a special method, SOURCE, that will use the same method to invoke the subscriber that was used to invoke the topic.

HTTP Authorization

The key, if one is provided, will be included as a bearer on the Authorization header.

HTTP Headers

In addition to the payload, additional headers will be added to the HTTP request to identify where the request came from:

  • X-Topic-Chain A comma-separated list of topic ids the event has traversed. Used to identify source, as well as prevent circular references.
  • X-Topic-Id The id of the topic invoking the subscription
  • X-Topic-Name The name of the topic invoking the subscription
  • X-User-Id The id of the user who owns the topic and subscription
  • X-Router-Signature Router signature. See Advanced section for more details.

The response will be recorded, and can be used again by the topic's invoker.

Details

  • By default, the HTTP handler will follow redirects, up to 4 times
  • The request will timeout in 5 seconds

Example Request

POST / HTTP/1.1
User-Agent: UbSub/1.0
X-Topic-Chain: 94jkNna,B1xFdvBv4b
X-Topic-Id: B1xFdvBv4b
X-User-Id: 4uHAh4nan
X-Topic-Name: test
Authorization: Bearer mykey
host: localhost:8080
accept: application/json
content-type: application/json
content-length: 2
Connection: close

{...payload...}

Topic Chaining

Sometimes it makes sense for one topic to invoke another topic. This is called topic chaining.

While it works fine to simply copy-paste the HTTP url of the other topic, there's a shorthand: topic://<topicId>?key=<key>.

Example: topic://Byg2kKB3SZ?key=HJ3ytS3SW

If there is no key, you can simply leave it off. You are not required to add a key if you are sending it to a topic you own.

EMail

You can trigger a simple email to be sent (serialized JSON) with the following format: mail://person@example.com

Optionally, you can add parameters: (eg. mail://person@example.com?subject=hi)

Parameters

  • subject Specify the subject line of the email (Default: Topic Id)
  • from The name that should be on the from line (Default: User Id)
  • bodykey The key to grab the body of the email from. (Default: Raw JSON)

SocketIO

SocketIO is the preferred method for on-the-fly subscribing to a topic. It isn't supported directly by the router, but rather, a supporting component.

There are two ways to connect/subscribe to a socket.

Subscribing via Query Params

When connecting via SIO, connect directly to the url /socket?userId=xxx&topicId=yyy&userKey=zzz.

Optionally, you can provide a name param to name the socket as well.

If you connect to specific topic via the handshake mechanism (query params), and there is an error, an event called handshake-error will be emitted, and the socket will be immediately disconnected.

const io = socketio('https://socket.ubsub.io/socket?userId=xxx&topicId=yyy&userKey=zzz');
io.on('connect', (socket) => {
    io.on('handshake-error', err => {
      console.error(err);
      // After this event, it will immediately be disconnected
    });
    io.on('event', data => {
        console.log('EVENT!');
        console.dir(data);
    });
});

Subscribing After Connection

The other option, is to connect to just /socket, and emit a packet on connection:

Example client:

const io = socketio('https://socket.ubsub.io/socket');
io.on('connect', (socket) => {
    io.emit('subscribe', {
        userId: 'xxx',
        userKey: 'xxx',
        topicId: 'xxx',
        name: 'my socket', // OPTIONAL name
    }, (err, data) => { // OPTIONAL callback
        if (err)
            console.log('ERROR: ' + err);
        console.dir(data); // contains {connectionId, subscriptionId, listenerId}
    });

    // Unsubscribe a listener from a given subscription
    io.emit('unsubscribe', {
      listenerId: '...'
    }, (err) => {});

    io.on('event', data => {
        console.log('EVENT!');
        console.dir(data);
    });
});

Technically you can combine both strategies.

Event Payload

When receiving an event that is sent to the subscription, it will be in the following form:

{
  "topicId": "abc",
  "payload" : {...}
}

Emitting an Event

You can also emit an event to any topic directly over the socket. Simply emit an event with the following data:

{
  "topicId" : "abc",
  "topicKey" : "def", // optional topic key
  "payload" : {...}
}

Shutting down

Sometimes it is necessary to request the server disconnect the client to mae sure all the data has been received first. To do this, simply emit the event shutdown and the client will be disconnected.

UDP

Do not confuse the udp:// protocol with the IoT protocol. The latter is secure and encrypted. More details can be found here.

Version 0 (Keyless)

WARNING: The UDPv0 protocol is not secure. Anyone can watch packets over-the-wire, and you are subject to a man-in-the-middle attack. Please use https for better security.

IMPORTANT: Unlike https, UDP does not wait for the payload to be acknowledged or delivered in any way. This method should be considered lossy, but good when performance or compatibility are important factors.

UDP is added for support for and low-level applications.

Example subscriber uri: udp://example.com:1234/a/b/c

Because a UDP subscriber doesn't wait for a response, the response in the topic invoke will look like this:

{
  "response": {
    "bytesSent": 105,   // Number of bytes sent
    "bufferSize": 105   // Number of bytes that were attempted to be sent
  },
  "subscription": {
    "id": "...",        // The ID of the subsription
    "topicId": "..."    // The ID of the topic
  }
}

The payload is formatted similar to HTTP, with \n being the delimiter. \n\n will be found directly before the payload. In the future, more header-like lines may be added.

Example:

POST /path
SUBID abcdef

{...JSON payload...}

Version 2/3 (For IoT)

The specification and details for UDPv3 can be found here.

It provides in additional functionality such as guaranteed-delivery, encryption/security/validation, NAT negotiation, etc.

C++ Implementation for Embedded Platforms

Store

The store service allows you to store small pieces of information. See store for details.

Void

Run a subscription, but always succeed, and don't send the data anywhere.

The response will be the parsed form of the requested query and the post-template payload.

Example: (void://test?v=1&b=2)

"response": {
  "void": {
    "protocol": "void",
    "hostname": "test",
    "path": "/",
    "query": "v=1&b=2"
  },
  "payload": {
    "nesting": {
      "a": 1233
    }
  }
}

MQTT

UbSub supports MQTT by proxying through a Eclipse Mosquitto.

Go to mqtt for more information.