Channel Streams and Typing Indicators

Last updated 14 days ago

In addition to messages, Mitter.io also supports sending small packets of information meant to provide additional, real-time information that is not significant enough to be persisted and/or queried. Mitter.io supports this using a feature called 'Channel Streams'. Every channel can have multiple channel streams mapped to it and custom channel streams can be created for Mitter.io applications. Example use-cases include:

  1. Typing indicators - Channel streams can be used to send information about when a user is typing. **

  2. Pointer tracking data - For example when making a collaborative drawing board channel streams can be used to send information regarding the location of the mouse pointer of individual users.

  3. Chunks in a multimedia stream - When streaming audio/video, individual chunks can be sent over channel streams.

** There is separate reserved channel stream for sending typing indicators. Refer to the section below on Typing indicators for more information.

Criteria for using channel streams

In the examples above, channel streams are the best fit over messages for the following reasons:

  1. Real-time significance only - The significance of sending the data is only when it is instantaneous. Both of them would not be required to be queried or to be displayed a trail of.

  2. Context-free - Messages are not context free because conversation builds a context. Both the examples do not require a strict ordering or the context within other similar items that are sent over the channel stream.

  3. Recoverable state and loss tolerance - If building state using stream data, if there is a provision to recover state then channel streams are a good example. For instance, if every 20 stream datum sent an absolute mouse pointer location was sent or if a keyframe for the multimedia stream was sent then the state at that point in time can be recovered using it. For use-cases that are tolerant to loses in communication and the required state can be recovered then it is a good use-case for channel streams

Reserved channel streams

There is only one channel stream that is reserved and is automatically created for every channel:

  1. .typing-indicator-stream Used to send a signal when a user has started typing. Refer to the section on typing indicators for more information.

Models

Channel Stream

A channel stream has a very simplified model:

{
"streamId": "56gil-asLHk-j3pKl-ndYQn",
"type": "mitter.streams.BroadcastObjectStream",
"supportedContentTypes": ["application/json"]
}

The type could be overridden to anything you want, internally it is not processed.

Context Free Message (Stream data)

The data that is sent to a channel stream is called a ContextFreeMessage. The model of the same is:

{
"contentType": "application/json",
"context": "pointer-location-update",
"senderId": "puRF7-QXnH5-A268z-kx7qq",
"data": {
"hello": "world"
}
}

The difference of a ContextFreeMessage from a regular message is that a context-free message is never persisted, does not contain an identifier and cannot be retrieved. A context-free message is delivered purely on a best-effort basis and there are no guarantees on delivery of the same. As opposed to messages context free messages are delivered much faster and are only delivered on messaging pipelines. For clients using HTTP polling, context free messages or messages from a stream cannot be fetched.

A context is provided to give a categorization to the type of message that was sent. For example, if on a stream you were sending two kind of messages - one containing only the differences in the mouse pointer from the last location and one where an absolute location was provided, then these two type of messages can be coded as two different contexts.

Pipeline payload

Context free messages or stream data can be received only over messaging pipelines like FCM, APNs, WebSockets etc. On a client the message is delivered confirming to the following model:

{
"channelId": "1CkkG-1qMig-5FsQD-9Tz45",
"streamId": "56gil-asLHk-j3pKl-ndYQn",
"streamData": {
"contentType": "application/json",
"context": "pointer-location-update",
"senderId": "puRF7-QXnH5-A268z-kx7qq",
"data": {
"hello": "world"
}
}
}

Typing indicators

To support typing indicators, whenever a user is typing a stream data is to be sent to the stream .typing-indicator-stream for the channel. It should follow the structure:

POST https://api.mitter.io/v1/channels/1CG-1s/streams/.typing-indicator-stream
{
"contentType": "text/plain",
"context": "mitter.ssd.UserTyping",
"senderId": "puRF7-QXnH5-A268z-kx7qq"
}

Clients should debounce this call to send out typing indicators and we recommend that they are sent out only once in about 5 seconds.

On receiving a payload of this type (refer to the documentation for the SDK you are using for receiving messaging pipeline payloads), the receiving client considers the user specified in the senderId field to be in typing status for a specified amount of time (we recommend this time to be 7 seconds). If during this time interval (before the user is reset to a non-typing state) if another channel stream datum is received for the same user, this timer should be reset.

Channel Stream API reference

Create a new channel stream

You can create a new channel stream for your purposes if the reserved channel streams do not suffice. To create a channel stream the create_channel_stream privilege is required, which is always granted to .system (i.e. when using an application access key/secret).

POST https://api.mitter.io/v1/channels/{channelId}/streams
{
"streamId": ".. your stream id ..",
"type": "mitter.streams.BroadcastObjectStream",
"supportedContentTypes": ["application/json"]
}

On a successful call the server returns the Stream object back, populating an identifier if you did not provide one.

200 OK
{
"streamId": "1CkkG-1qMig-5FsQD-9Tz45",
"internalId": "X6uCD-OLyuO-TUQnJ-J0kWV",
"type": "mitter.streams.BroadcastObjectStream",
"supportedContentTypes": ["application/json"]
}

NOTE You can omit supportedContentTypes to make the stream accept data in any type.

Send stream data

Data is sent to a channel stream by sending a context free message. To send message to a stream the client needs to have send_to_channel privilege (if the sender id is the same as the user making the call) or the send_as_other_to_channel (if the sender id is different than the user making the call). By default all users have the send_to_channel privilege granted to them and .system always has send_as_other_to_channel granted to it. Do note that this is the same privilege that is checked for sending messages to a channel

NOTE We currently do not support access control over specific streams i.e. a user granted send_to_channel can send messages to all streams in that channel. We are currently working on having stream specific privileges.

POST https://api.mitter.io/v1/channels/{channelId}/streams/{streamId}
{
"contentType": "application/json",
"context": ".. your context ..",
"senderId": "puRF7-QXnH5-A268z-kx7qq",
"data": {
"hello": "world"
}
}

On a successful call the server returns the same message back with any defaults populated (do note that context free messages do not have an identifier

200 OK
{
"contentType": "application/json",
"context": ".. your context ..",
"senderId": "puRF7-QXnH5-A268z-kx7qq",
"data": {
"hello": "world"
}
}

Receiving stream data

Receiving stream data is not supported via HTTP and stream data can be received only via messaging pipelines. To receive stream data over a channel stream all users with read_from_channel privilege are marked as delivery recipients. For the shape of the received payload, refer to the section pipeline payload.