Read Data Stream
Overview
In the Terra Streaming Protocol, to read a data stream, a consumer connection is formed between a program and the Terra WebSockets service. The program is then able to receive real-time data from any wearable which is currenty connected to Terra through a producer connection.
The following describes the steps required to setup a consumer connection to the Terra WebSockets service. See Setting up a WebSocket Consumer for a specific example written in Node.js.
Connecting
Upon opening a websocket connection to the server, you will immediately be sent an Op 2 HELLO
payload containing the heartbeat interval (in milliseconds) that the client should use when sending heartbeat messages to the server.
{
"op": 2,
"d": {
"heartbeat_interval": 40000
}
}
Once this payload has been received by the client, it is expected to begin heartbeating. See below.
Heartbeating
Heartbeating is effectively a PING/PONG
chain which is communicated to the server over a regular interval to inform the server that the connection is still in use.
The first heartbeat should be sent after heartbeat_interval * jitter
milliseconds, where jitter
is a random value between 0.1
and 1.0
. After the initial heartbeat is sent, the client should continue heartbeating at the precise interval given in the HELLO
payload. You do not need to account for network latency as the server gives the client some leeway either side of the interval before closing a potentially zombied connection.
Whenever the server receives an Op 0 HEARTBEAT
, it will reply with an Op 1 HEARTBEAT_ACK
message, indicating that the heartbeat was successfully received. If the client does not receive this response, the connection should be closed and a new connection established.
{
"op" 0
}
{
"op": 1
}
Authenticating
Authenticating the websocket connection is done through sending an IDENTIFY payload through the connection which contains a token generated by hitting the appropriate token generation endpoint.
Identify Data Schema
Field Name | Type | Description |
---|---|---|
token | String | Authentication token generated from the appropriate endpoint. |
type | Integer | Connection type. Value from the IdentifyType enum. |
IdentifyType Enum
Name | Value |
---|---|
User (Producer) | 0 |
Developer (Consumer) | 1 |
{
"op": 3,
"d": {
"token": "OTYwNWFi5ZWQMTAxMjg0Y2Qw.gzrPzZcS3Gy8QDOxbiPRwu30PTB3VxW0eE",
"type": 0
}
}
If identification is successful, the server will respond with an Op 4 READY payload:
{
"op": 4
}
At this point, the connection is ready to send/receive data to/from the server.
Websocket Commands
There are two commands you can send through the websocket connection other than those used for authentication and heartbeating. These are Op 6 SUBMIT and Op 7 REPLAY.
The SUBMIT command is used by a producer client connection to send data to the server for dispatch to consumers.
The REPLAY command is used by a consumer client to request the re-sending of payloads between the given seq
lower (and optionally upper) bounds. This is useful when the websocket connection may have closed erroneously so the consumer client missed out on a couple of payloads during that period.
If a producer connection attempts to use the SUBMIT command (and likewise if a consumer attempts to use the REPLAY command) the connection will be immediately closed by the server with a close code of 4004
.
Replay Data Object Structure
Field Name | Type | Description |
---|---|---|
after | Long | Replay all payloads after this seq value |
before? | Long | Optional upper bound for replaying of payloads |
Example Payloads
{
"op": 7,
"d": {
"after": 28,
"before": 43
}
}
{
"op": 6,
"d": {...},
"t": "HEART_RATE"
}
Receiving Data
Data can only be received through consumer connections. When new data is available, an Op 5 DISPATCH payload will be send through the websocket connection containing all information available for the event.
All DISPATCH events will always contains a uid
key, which will contain the Terra user ID of the user that the data belongs to. It will also contain a t
key, which will contain the event type, i.e. the type of data that the event represents (e.g. HEART_RATE
etc). The d
sub-object will contain the actual timestamps and values for the data.
{
"op": 5,
"d": {
"t": "2022-05-04T10:26:11.268507+01:00",
"val": 95
},
"uid": "8e864e3a-979a-4d04-b4e9-b6d020f20ba0",
"seq": 73,
"t": "HEART_RATE"
}
Updated about 1 year ago