NAV
typescript shell

Introduction

Before proceeding, please take a moment to register an account with NoLag. This will make it easier to follow along.

To stay up-to-date with future updates and get help, we encourage you to join our Discord server.

What is different about NoLag?

NoLag provides a seamless plug-and-play solution that enables real-time communication between devices.

Our core feature is "Reverse Queries".

Reverse query is where a publisher transmits messages on a specific topic attached to a set of Identifiers. Subscribers can they listen to the topic and a list of identifier based on the ACL credentials.

Supported languages

On the right, you'll find a list of language flavors. You can use the package manager commands listed to install the NoLag SDK.

If you're interested in creating your own integration, be sure to check out the NoLag Transport Protocolsection.

npm i nolagjs
yarn add nolagjs

Quick Example

Check out NoLag in action, we created a few demo examples.

Subscriber

Rider subscribing to driver location updates

/**
 * ----- Create NoLag Tunnel connection -----
 * */
import {
  WebSocketClient,
  stringToArrayBuffer,
  uint8ArrayToString,
} from "nolag";

import type { ITopic, ITunnel, IResponse } from "nolag";

const accessToken: string = "<your_device_access_token_goes_here>";

const nolagInstance: ITunnel = await WebSocketClient(accessToken);

/**
 * ----- SUBSCRIBE to Topic and set some identifiers to listen to -----
 */
const rideShareRider: ITopic = nolagInstance.subscribe("rideShareDriver",  {
  OR: [
    "booking_id_1234",
  ],
});


/**
 * ----- RECEIVE data on Topic name -----
 */
rideShareRider.onReceive((received: IResponse) => {
  const { data, identifiers, topicName, presences } = received;
  const stringData: string = uint8ArrayToString(data);
  const receivedData = JSON.parse(stringData);
  console.log(receivedData);
  //{
  //   driverCurrentLocation: {
  //     lat: "1234",
  //     lng: "34564",
  //   },
  // }
  console.log(identifiers);
  // ["booking_id_1234"]
  console.log(topicName);
  // rideShareDriver
  console.log(presences);
  // ["driver_id_6a9d03f5-bc0f-4516-9b51-c223a6cac0d2"]
});

Publisher

Driver publishing location to Rider. Notice the Presence property. Presence is a mechanism to update the Rider of the Drivers presence without having to constantly ping the Rider.

/**
 * ----- PUBLISH some data to a topic and grouping of identifiers -----
 */
const rideShareDriverPayload: string = JSON.stringify({
  driverCurrentLocation: {
    lat: "1234",
    lng: "34564",
  },
});

// payload as ArrayBuffer
const payloadArrayBuffer: ArrayBuffer = stringToArrayBuffer(rideShareDriverPayload);

// identifiers
const identifiers: string[] = ["booking_id_1234"];

nolagInstance.publish("rideShareDriver", payloadArrayBuffer, identifiers);

Getting Started

Before we can start coping and pasting example code we first have to set up the environment.

Follow the below step

  1. Create a Project
  2. Create a Tunnel
  3. What are NQL identifiers?
  4. Create a Topic
  5. Authentication
  6. Usage and Billing

Create a Project

To get started, we need to create a new project. With a NoLag project, you can manage the following:

Create a Tunnel

The Tunnel serves as the pathway for data transmission between devices.

Some key points to keep in mind:

Sandbox Tunnels

Sandbox Tunnels function exactly the same as regular Tunnels, with the only difference being resource limitations. All sandbox Tunnels share the same resource limits.

What are NQL identifiers?

NQL(NoLag Query Language) identifiers can be thought of as sub-Topics within the NoLag Query Language. These identifiers act as query points within the NoLag message broker and consist of a list of values.

this.playerMovement.addIdentifiers({
  OR: [
  "clanId:9482f8ee-26d0-4a92-97d3-95e99c764e59",
  "surroundingTile:800:802",
  "biome-4",
]});

this.playerMovement.removeIdentifiers(["surroundingTile:800:802"]);

As a Subscriber
The Subscriber can listen to the Topic and the list of identifiers attached to it. A list of identifiers represents a OR operation. Ex. IdentifierOne OR IdentifierTwo

As a Publisher
The Publisher can send messages to the Topic and optionally specify one or more identifiers..

NQL identifiers
NQL identifiers are dynamic, meaning they can be added or removed from a Topic implemented by a device.

Flow diagram

In the diagram you can see two wind turbines each publishing one message to the Topic "turbineOutput" and each with a different set of NQL identifiers.

NoLag will then distribute the messages to the Subscribers using the NQL identifiers.

Create a Topic

Topics are the events or triggers that a Subscriber will listen to and a Publisher will send data to. Topics are attached to a Tunnel, which is grouped under a Project.

Topics are static

Topics are static and created in the NoLag portal or via API calls. They can only be changed or removed from a Tunnel via the portal or API calls. Having static Topics and dynamic NQL identifiers makes it easier to build secure, scalable real-time applications.

While Topics are static, you can easily set or remove a Topic from a subscriber. Topics have several features, including:

Authentication

Device access Tokens are a key feature of NoLag and the cornerstone for securing device connections. All connections to a Tunnel require a Device Token, which can have several options:

Usage and Billing

Message Size

There are no publishing frequency limits but there are payload size limits.

Message transport data size can not exceed 50KB. Exceeding the allowed transport size will disconnect your device from the Tunnel.

Message transport size is made up of "topicName", "identifiers" and "payload".

Connection cost

Client will be billed for the number of seconds a device is connected to a Tunnel server.

Data transfer cost

Clients will be billed for the number of bytes egressing the Tunnel servers. This will also include data being sent between Tunnel locations.

Ex. If all your clients are in one region you will only be billing for data leaving the Tunnel server.

Ex. If you have clients all over the world and data is being sent between Tunnels servers, you will be billed for data leaving each Tunnel location and also data traveling between Tunnel locations.

Billing period

The billing period is based on a monthly cycle and starts on the first day of the month. At the end of each billing cycle, clients will receive an invoice for their usage.

Pricing model

NoLag follows a usage-based pricing model, meaning that clients are only charged for the resources they consume during the billing period. There are no upfront costs or long-term commitments.

Billing details

Clients can view their usage and billing details in the NoLag dashboard, which provides real-time visibility into their data transfer and connection costs. The dashboard also allows clients to set up alerts and notifications for cost thresholds and usage limits.

Client SDK

Connecting to a Tunnel


npm i nolagjs

yarn add nolagjs

pnpm add nolagjs

Install your flavour of NoLag SDK from your preferred package manager.

Client instance

Import function
WebSocketClient
Argument Required Type Description
deviceToken true string Device token generated via NoLag portal or API.

Return

ITunnel

Tunnel Instance

Tunnel Instance

// import package
import { WebSocketClient } from "nolag";

import type { ITunnel, ITopic } from "nolag";

const deviceToken: string = "<device_token_goes_here>";

// Connect to Tunnel
const nolagClient: ITunnel = await WebSocketClient(deviceToken);

// get device token ID
console.log(nolagClient.deviceTokenId);

Methods

  1. subscribe
  2. publish
  3. unsubscribe
  4. getTopic
  5. disconnect

Instances

  1. Topic

Properties

  1. deviceTokenId

Callbacks

  1. onReceive
  2. onDisconnect
  3. onReconnect
  4. onError

Subscribe to a Topic

Subscribe to Topic

const topicOne: ITopic = nolagClient.subscribe("topicOne");

Subscribe to Topic with NQL identifiers attached

const topicTwo: ITopic = nolagClient.subscribe("topicTwo", {
  OR: [
    "identifier_1",
    "identifier_2",
    "identifier_3",
]});

Back to Index

You can subscribe to any valid Topic name. Topic names are created in the NoLag portal or via an API call.

Method call

Instance Method name
TunnelInstance subscribe
Argument Required Type Description
topicName yes string Name of the topic you want to subscribe to.
identifiers no INqlIdentifiers List of NQL identifiers attached to Topic Name

Return

ITopic

Publish on a Topic

Publish message

import { stringToArrayBuffer } from "nolag";
// required
const topicName: string = "topicTwo";
// required
const payload: ArrayBuffer = stringToArrayBuffer("This is your first message");
// optional
const identifiers: IErrorsModel = {
  OR: ["identifier_4"]
};

nolagClient.publish(topicName, payload, identifiers);

Back to Index

Instance Method name
TunnelInstance publish
Argument Required Type Description
topicName yes string Name of the topic you want to send a message to.
payload yes ArrayBuffer Data to send via Topic name.
identifiers no [...value{string}] List of NQL identifiers attached to Topic Name

Unsubscribe from Topic

Unsubscribe

nolagClient.removeTopic("topicOne");

Back to Index

Method call

Instance Method name
TunnelInstance removeTopic
Argument Required Type Description
topicName yes string The name of the topic you want to unsubscribe from.

Return

boolean

Get Topic instance

Get Topic

const topicOne: ITopic = nolagClient.getTopic("topicOne");

Back to Index

Method call

Instance Method name
TunnelInstance getTopic
Argument Required Type Description
topicName yes string The name of the topic instance.

Return

ITopic

Disconnect

Disconnect

nolagClient.disconnect();

Back to Index

Method call

Instance Method name
TunnelInstance disconnect

Return

ITunnel

Receive message callback

Receive message

import { uint8ArrayToString } from "nolag";

nolagClient.onReceive((received) => {
  const { data, topicName, nqlIdentifiers, presences } = received;
  const parseData = JSON.parse(uint8ArrayToString(data));
});

Back to Index

Instance Method name
TopicInstance onReceive
Argument Required Type Description
callbackFn yes Function Callback will fire on message received

Callback Function

Argument Required Type Description
received yes ITransport

Disconnect callback

On Disconnect

nolagClient.onDisconnect(() => {
  // lost connection
});

Back to Index

Method call

Instance Method name
TunnelInstance onDisconnect
Argument Required Type Description
callbackFn yes Function Callback will fire after connection loss

Return

ITunnel

Re-connect callback

On Reconnect

nolagClient.onReconnect(() => {
  // successful connection made
});

Back to Index

Method call

Instance Method name
TunnelInstance onReconnect
Argument Required Type Description
callbackFn yes Function Callback will fire when device reconnects

Return

ITunnel

On error callback

On Error

nolagClient.onError((errors: ConnectionErrors) => {
  // received errors
  console.log(errors);
});

Back to Index

Method call

Instance Method name
TunnelInstance onError
Argument Required Type Description
callbackFn yes Function Callback will fire on any connection errors

Callback Function

Argument Required Type Description
errors yes ConnectionErrors Errors sent from message broker

Return

ITunnel

Properties

Device Token ID

Device Token ID

console.log(nolagClient.deviceTokenId);

Back to Index

Property Description
deviceTokenId Device Token is a unique identifier that is used to authenticate a device and grant it access to a specific Tunnel. It is attached to the token used to connect to the Message Broker, allowing the device to establish a secure and authorized connection.

Topic Instance

Topic Instance

let topicTwo: ITopic = nolagClient.subscribe("topicTwo");
// or if you already subscribed to "topicTwo" then use the below method
topicTwo: ITopic = nolagClient.getTopic("topicTwo");

When you subscribe to a Topic you get access to the topic instance. You can also access the Topic instance via the Tunnel instance using the getTopic method.

Methods

  1. addIdentifiers
  2. removeIdentifiers
  3. presence
  4. publish
  5. unsubscribe

Callbacks

  1. onReceive

ADD NQL identifiers

Back to Index

Add Identifiers to Topic

topicTwo.addIdentifiers({
  OR: [
  "identifier_1",
  "identifier_2",
  "identifier_3",
  "identifier_4",
]});
Instance Method name
Topic addIdentifiers
Argument Required Type Description
identifiers true [...value{string}] Extra list of strings that the device will be listening.

Return

ITopic

REMOVE NQL identifiers

Remove identifiers

topicTwo.removeIdentifiers(["identifier_1", "identifier_2"]);

Back to Index

Instance Method name
Topic removeIdentifiers
Argument Required Type Description
identifiers true [...value{string}] Remove identifiers from your subscription

Return

ITopic

Presence

Add device presence

topicTwo.setPresence("userId");

What is Presence

Presence is data you attach to a device that is subscribed to a Topic. If you set Presence data on a Topic, and another device subscribes to the same Topic with the same Identifiers. Both Devices will be sent each others "Presence Data".

Ex. Users connecting to a chat room. As soon as a user connects you will receive their presence data, and they will receive yours. You can attach any data which could be a UUID, the users name or a URL to an avatar.

Back to Index

Instance Method name
Topic setPresence
Argument Required Type Description
data true string Any data that you would like to attach to a device

Return

ITopic

Topic publish

Publish message

import { stringToArrayBuffer } from "nolag";

// required
const payload: ArrayBuffer = stringToArrayBuffer("This is your second message");
// optional
const identifiers: INqlIdentifiers = {
  OR: ["identifier_4"]
};

topicTwo.publish(payload, identifiers);

Back to Index

Instance Method name
TopicInstance publish
Argument Required Type Description
payload true string Message you want to send to the Topic.
identifiers optional [...value{string}] Send messages only to these identifiers

Return

ITopic

Receive message callback

Receive message

import { uint8ArrayToString } from "nolag";

topicTwo.onReceive((received) => {
  const { data, topicName, nqlIdentifiers } = received;
  const parseData = JSON.parse(uint8ArrayToString(data));
});

Back to Index

Instance Method name
TopicInstance onReceive
Argument Required Type Description
callbackFn yes Function Callback will fire on message received

Callback Function

Argument Required Type Description
received yes ITransport

Unsubscribe

Unsubscribe

topicTwo.unsubscribe();

Back to Index

Method call

Instance Method name
Topic unsubscribe

Return

boolean

API

Create API instance

API instance is used for all API calls.

import { Api, IApiTunnel } from "nolag";

const apiKey = "[api_key_goes_here]";

const nolagApi: IApiTunnel = await Api(accessToken);

Before you can make use of the API you need to generate a API token in the NoLag portal.

Methods

  1. Message Broker
    1. publish
  2. Tunnel methods
    1. List Project Tunnels
  3. Topic methods
    1. createTopic
    2. getTopic
    3. updateTopic
    4. deleteTopic
    5. listTopics
  4. Device methods
    1. createDevice
    2. getDevice
    3. updateDevice
    4. deleteDevice
    5. listDevices

Project Tunnels

Returns a list of Tunnels attached to a Project

curl "https://api.nolag.app/v1/tunnels" \
  -X POST \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi.tunnels();

Back to Index

HTTP Request

POST https://api.nolag.app/v1/tunnels

Method

Instance Method name
ApiTunnel tunnels
Argument Required Type Description
tunnelQuery no ITunnelQuery Query params for Tunnels

Response

Argument Type
records [...ITunnelModel]
pagination IPagination

Tunnel Topics

Topics attached to a tunnel

Topic Create

Returns a list of Topics attached to a Tunnel

curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics" \
  -X POST \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
  -d "[payload_goes_here]"
const payload: ITopicModel = {
  name: "TestTopic",
  status: "active",
  type: "active",
  triggerApi: "active",
  hydrateApi: "active",
  noEcho: false,
};

await nolagApi.tunnel("[tunnel_id_goes_here]").topic.createTopic(payload);

Back to Index

HTTP Request

POST https://api.nolag.app/v1/tunnels/:tunnelId/topics

Method

Instance Namespace Method name
ApiTunnel tunnel.topic createTopic
Argument Required Type Description
topicModel yes ITopicModel

response

ITopicModel

Topic Get Record

Get all records for

curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId" \
  -X GET \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .topic.getTopic("[topic_id_goes_here]");

Back to Index

HTTP Request

GET https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId

Method

Instance Namespace Method name
ApiTunnel tunnel.topic getTopic
Argument Required Type Description
TopicId yes string

response

ITopicModel

Topic Update

Update Topic attached to a Tunnel

curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId" \
  -X PATCH \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
  -d "[payload_goes_here]"
const payload: ITopicModel = {
  name: "TestTopic",
  status: "active",
  type: "active",
  triggerApi: "active",
  hydrateApi: "active",
  noEcho: false,
};

await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .topic.updateTopic("[topic_id_goes_here]", payload);

Back to Index

HTTP Request

PATCH https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId

Method

Instance Namespace Method name
ApiTunnel tunnel.topic updateTopic
Argument Required Type Description
topicModel yes ITopicModel

response

ITopicModel

Topic Delete

Delete a Topic

curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId" \
  -X DELETE \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .topic.deleteTopic("[topic_id_goes_here]");

Back to Index

HTTP Request

DELETE https://api.nolag.app/v1/tunnels/:tunnelId/topics/:topicId

Method

Instance Namespace Method name
ApiTunnel tunnel.topic deleteTopic
Argument Required Type Description
topicModel yes ITopicModel

response

ITopicModel

Topic List

Get a list of Topics

curl "https://api.nolag.app/v1/tunnels/:tunnelId/topics?[query_params_go_here]" \
  -X GET \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .topic.listTopics("[topic_id_goes_here]");

Back to Index

HTTP Request

GET https://api.nolag.app/v1/tunnels/:tunnelId/topics?[query_params_go_here]

Method

Instance Namespace Method name
ApiTunnel tunnel.topic listTopics
Argument Required Type Description
topicQuery no ITopicQuery

Response

Argument Type
records [...ITopicModel]
pagination IPagination

Tunnel Devices

ACL management for Tunnel devices and Access Tokens

Device Create

Create a new device attached to a Tunnel

curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices" \
  -X POST \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
  -d "[payload_goes_here]"
const payload: IDeviceTokenModel = {
  name: "TestDevice",
  accessPermission: EAccessPermission.PubSub,
  staticTopics: null,
  lockTopics: false,
  expireIn: 1000,
  expireIn: 1000,
  loadBalance: ELoadBalanceType.RoundRobin,
};

await nolagApi.tunnels("[tunnel_id_goes_here]").devices.createDevice(payload);

Back to Index

HTTP Request

POST https://api.nolag.app/v1/tunnels/:tunnelId/devices

Method

Instance Namespace Method name
ApiTunnel tunnels.devices createDevice
Argument Required Type Description
deviceTokenModel yes IDeviceTokenModel

response

IDeviceTokenModel

Device Get Record

Get a single device using Device Token Id

curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId" \
  -X GET \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .devices.getDevice("[device_id_goes_here]");

Back to Index

HTTP Request

GET https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId

Method

Instance Namespace Method name
ApiTunnel tunnels.devices getDevice
Argument Required Type Description
deviceTokenId yes string

response

IDeviceTokenModel

Device Update

Update device attached to the Tunnel

curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId" \
  -X PATCH \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
  -d "[payload_goes_here]"
const payload: IDeviceTokenModel = {
  name: "TestDevice",
  accessPermission: EAccessPermission.PubSub,
  staticTopics: null,
  lockTopics: false,
  expireIn: 1000,
  loadBalance: ELoadBalanceType.RoundRobin,
};

await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .devices.updateDevice("[device_id_goes_here]", payload);

Back to Index

HTTP Request

PATCH https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId

Method

Instance Namespace Method name
ApiTunnel tunnels.devices updateDevice
Argument Required Type Description
deviceTokenModel yes IDeviceTokenModel

response

IDeviceTokenModel

Device Delete

Delete a device using device ID

curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId" \
  -X DELETE \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .devices.deleteDevice("[device_id_goes_here]");

Back to Index

HTTP Request

DELETE https://api.nolag.app/v1/tunnels/:tunnelId/devices/:deviceTokenId

Method

Instance Namespace Method name
ApiTunnel tunnel.devices deleteDevice
Argument Required Type Description
deviceId yes string

response

IDeviceTokenModel

Device List

Get a list of devices based of query params.

curl "https://api.nolag.app/v1/tunnels/:tunnelId/devices?[query_params_go_here]" \
  -X GET \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: application/json"
await nolagApi
  .tunnels("[tunnel_id_goes_here]")
  .devices.listDevices({
    name: "deviceOne",
  });

Back to Index

HTTP Request

GET https://api.nolag.app/v1/tunnels/:tunnelId/devices?[query_params_go_here]

Method

Instance Namespace Method name
ApiTunnel tunnels.devices listDevices
Argument Required Type Description
deviceListQuery yes IDeviceListQuery

Response

Argument Type
records [...IDeviceTokenModel]
pagination IPagination

Publish messages

Publish messages to the NoLag via an HTTP request

curl "https://tunnel.nolag.app/tunnels/:tunnelId/publish" \
  -X POST \
  -H "X-API-Key: [api_key_goes_here]"
  -H "Content-Type: text/plain"
  -d "[payload_goes_here]"
import { stringToArrayBuffer, IHttpPublish } from "nolag";

const payload: IHttpPublish = {
  data: stringToArrayBuffer(
    JSON.stringify({
      bulbStatus: true,
    })
  ),
  tunnelName: "topicTwo",
  identifiers: ["identifier_1", "identifier_4"],
};

await nolag.publish(payload);

Back to Index

HTTP Request

POST https://tunnel.nolag.app/tunnels/:tunnelId/publish

Method

Instance Namespace Method name
ApiTunnel tunnels publish
Argument Required Type Description
httpPublish true IHttpPublish

Response

boolean

Webhooks

How it works

Webhook Types

  1. Trigger
  2. Hydrate

Triggers Webhook

Trigger webhook is triggered when a message is published to a Topic.

{
    topicName: 'factory',
    identifiers: [ '373d521118f04b85810f4bba88d14a46' ],
    deviceId: '2a39a946-4556-4f4d-bb48-ee11cab54d18',
    data: "{message: 'hello'}"
}

As the name implies, this webhook is triggered when a message is published to a Topic.

You attach a Trigger webhook to a Topic in the NoLag portal.

Received JSON data from NoLag

Argument Type Description
topicName string Topic name that actioned this trigger
identifiers [...string] NQL identifiers attached to the Topic name
deviceId string Which device actioned the trigger
data string Data triggered by Topic

Back to Index

Hydration Webhook

Hydration webhook is triggered when a device connects to NoLag.

{
    topicName: 'factory',
    identifiers: [ '373d521118f04b85810f4bba88d14a46' ],
    deviceId: '2a39a946-4556-4f4d-bb48-ee11cab54d18'
}

Hydrate device with data from an API end-point.

You attach a Hydrate webhook to a Topic in the NoLag portal.

Received JSON data from NoLag

Argument Type Description
topicName string Topic name that actioned this trigger
identifiers [...string] NQL identifiers attached to the Topic name
deviceId string Which device actioned the trigger

Hydration response

This can be in any data format. NoLag will pass this data to the device without modification.

Back to Index

Transport Protocol

If your project doesn't have SDK support yet, this guide will help you get set up.

Servers

We use GEO routing. All you need to do is reference this URL and our infrastructure will route the request to the closest NoLag node.

Websocket Tunnel URL

wss://tunnel.nolag.app/ws

Authentication sequence

The following steps explain the connection and authentication of a connecting device

  1. Device connects to NoLag
  2. NoLag sends back a SOH to the device
  3. The device sends SI with deviceAccessToken to NoLag
  4. (Only on re-connect) The device sends SI with deviceAccessToken and a SYN command to NoLag
  5. NoLag sends back ACK and the deviceTokenId

Example sequence seen from the device:

  1. SOH
  2. SI[deviceAccessToken]
  3. SI[deviceAccessToken]SYN <-- only on re-connect
  4. ACK[deviceTokenId]
  5. [transport_payload_here]

Transport Payload

Transport payload is how you communicate with NoLag. The payload consists of commands, and optionally device data to be sent.

[COMMAND][ACTION][GS][device_data]

Commands and device data are separated by a GS symbol.

NOTES:

Transport Example

Subscribe to Topic "MyTopicName", and set two identifiers, "identifierOne" and "identifierTwo".

[SUB]MyTopicName[VT]IdentifierOne[US]IdentifierTwo[US][FF]

Explanation:

Hex transport:

1A 4D 79 54 6F 70 69 63 4E 61 6D 65 0B 49 64 65 6E 74 69 66 69 65 72 4F 6E 65 1F 49 64 65 6E 74 69 66 69 65 72 54 77 6F 1F 0C

Commands

Connect to NoLag

Back to transport

NoLag will send a SOH command as soon as the device successfully connects

DEC HEX BIN Symbol Has Action
1 01 00000001 SOH NO

ASCII Example:

SOH

Authenticate on NoLag

Back to transport

Send device access token to NoLag to authenticate the device.

DEC HEX BIN Symbol Has Action
15 0F 00001111 SI YES

ASCII Example:

SI<deviceAccessToken>

Acknowledge

Back to transport

Acknowledges anything successfully. This could be a connection to NoLag or acknowledging a message was received.

DEC HEX BIN Symbol Has Action
6 06 00000110 ACK YES

ASCII Example:

ACK<any_acknowledgment_ID>

Reconnect to NoLag

Back to transport

We add the SYN symbol to the Authenticate on NoLag transport to re-stabling the device connection state. We use this when the device looses internet connection. This command will re-establish all Topic and Identifier subscriptions.

DEC HEX BIN Symbol Has Action
22 16 00010110 SYN YES

ASCII Example:

SI<deviceAccessToken>SYN

Subscribe to Topic only

Back to transport

Subscribe to a valid Topic. Valid Topics are created in the NoLag portal. Remember to add the FF command.

DEC HEX BIN Symbol Has Action
26 1A 00011010 SUB YES

ASCII Example:

SUB<ValidTopic>FF

Subscribe to Topic and Identifiers

Back to transport

Subscribe to a valid Topic and identifiers. VT command will always be followed by a list of Identifiers. List of Identifiers are separated by US. Remember to add the FF command.

DEC HEX BIN Symbol Has Action
11 0B 00001011 VT YES

ASCII Example:

SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USFF

Signify a list of data

Back to transport

We create a list of data as part of the transport with the US command. Here the pattern is slightly different. We suffix the command from the data.

DEC HEX BIN Symbol Has Action
31 1F 00011111 US YES

ASCII Example:

<identifierOne>US<identifierTwo>US

Handle device presence

Back to transport

Presence is a why for devices to discover one another that are listening to Topic and Identifiers, without needing to constantly ping devices. Presence signifies when a device connects to NoLag, and when they disconnect. We piggyback of the standard subscription transports to attach a devices presence.

DEC HEX BIN Symbol Has Action
14 0E 00001110 SO YES

ASCII Example:

Send presence: SO<presenceDataOne>

Receive presences: SO<presenceDataOne>US<presenceDataOne>US

Full send presence example:

SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USSO<presenceDataOne>FF

Full receive presence example:

SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USSO<presenceDataOne>US<presenceDataOne>USFF

Unsubscribe from Topic

Back to transport

Device stop listening to Topic name.

DEC HEX BIN Symbol Has Action
16 10 00010000 DLE NO

ASCII Example:

SUB<ValidTopic>DLE

Unsubscribe from Topic and Identifiers

Back to transport

Device stop listening to Topic Identifiers.

DEC HEX BIN Symbol Has Action
16 10 00010000 DLE NO

ASCII Example:

SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USDLE

Publish to a Topic

Back to transport

The GS command signifies data being sent or received by the device. We have to supply which Topic the data is attached to.

DEC HEX BIN Symbol Has Action
29 1D 00011101 GS YES

ASCII Example:

GS<deviceData>

Full example send and receive:

SUB<ValidTopic>GS<deviceData>

Publish to a Topic and Identifiers

Back to transport

The GS command signifies data being sent or received by the device. We have to supply which Topic and Identifiers the data is attached to.

DEC HEX BIN Symbol Has Action
29 1D 00011101 GS YES

ASCII Example:

GS<deviceData>

Full example send and receive:

SUB<ValidTopic>VT<identifierOne>US<identifierTwo>USGS<deviceData>

Types

  1. Enums
    1. EAccessPermission
    2. EStatus
    3. EAction
  2. Interfaces
    1. IPaginated
    2. IPagination
    3. IDeviceListQuery
    4. INqlIdentifiers
    5. IDeviceTokenModel
    6. IStaticTopic
    7. IHttpPublish
    8. ITunnelQuery
    9. IResponse
    10. ITopicModel
    11. ITopicApiModel
    12. ITopicQuery
    13. ITopic
    14. ITriggerRequest
    15. IHydrateRequest
    16. IErrorMessage
    17. IErrorsModel

Enums

EAccessPermission

Used to specify which type of Pub/Sub access the associated Device Token has.

Device permissions

Key Value Description
Subscribe "subscribe" Can only Subscribe
Publish "publish" Can only Publish
PubSub "pubSub" Can Publish and Subscribe

EStatus

Set the status of a Topic. Active, the Topic can be used. Inactive, Topic can not be used.

Key Value Description
Active "active"
Inactive "inactive"

ELoadBalanceType

How message will be delivered to devices sharing the same device token.

Key Value Description
RoundRobbin "roundRobin"

Interfaces

IPaginated

Back to Interfaces

Paginated result received from the API end-point.

Property Type Description
records [...DTO] List of records
pagination IPagination

IPagination

Back to Interfaces

Pagination details indicating the current status of your pagination query.

Key Type Description
page integer Current page
size integer Records per page
hasPrevious boolean From the current page, are there any previous records
hasNext boolean From the current page, are there any next records
total integer Total number of records

IDeviceListQuery

Back to Interfaces

Available query parameters to query a device list.

Key Type Description
deviceAccessToken string This token is your access token key
expireFromDate integer Find expire dates after this date
expireToDate integer Find expire dates before this date
name string Name of the Device
search string search for names
size integer Number of records on the page
page integer Page number

INqlIdentifiers

Back to Interfaces

Available query parameters to query a device list.

Key Type Description
OR [...value{string}] List of OR identifiers

IDeviceTokenModel

Back to Interfaces

Properties in creating or updating a Device Token.

Key Type Description
name string This token is your access token key
accessPermission EAccessPermission
deviceTokenId string Record ID
deviceAccessToken string This token is your access token key
tunnelId string Tunnel ID this device is attached to
staticTopics IStaticTopic
lockTopics boolean Page number
expireIn integer Expire in seconds from when the device token was created
expireDate integer Calculated date of when this will happen
loadBalance ELoadBalanceType Devices sharing the same device token will receive messages in a round robbin method

IStaticTopic

Back to Interfaces

Static Topics, are a group of Topic names and Identifiers. These are attached to a Device Token. In the scenario where the Device Token is locked, the Device only has access to its Static Topics.

Key Type Description
name string Topic name that static on the Device Token
identifiers [...value{string}] Static identifiers

IHttpPublish

Back to Interfaces

Sending messages to the Message Broker via HTTP call

Key Type Description
data ArrayBuffer Data received from Topic subscription
topicName string Topic name
identifiers string List of NQL identifiers

ITunnelQuery

Back to Interfaces

Query parameters for Tunnel resource

Key Type Description
status EStatus Status of Tunnels
size number Number of records in results
page number Page to view
search string Search for Tunnel name

ITransport

Back to Interfaces

Response received from Message Broker

Key Type Description
data Uint8Array Data received from Topic publish
topicName string Topic name
identifiers [...value{string}] Identifiers used for this received message
presences [...value{string}] List of current active devices represented by custom data set

ITunnelModel

Back to Interfaces

Topic properties used to creating or updating a model

Key Type Description
tunnelId string Tunnel ID
projectId string Topic name
status EStatus Status of Tunnel
name string Name of Tunnel
sandbox boolean Sandbox or production Tunnel

ITopicModel

Back to Interfaces

Topic properties used to creating or updating a model

Key Type Description
topicId string Topic ID
projectId string Topic name
tunnelId string
status EStatus Status of Topic
name string Name of Topic
triggerApi ITopicApiModel
hydrateApi ITopicApiModel
noEcho boolean Do not publish to Topic if device is also subscribed to the Topic

ITopicApiModel

Back to Interfaces

Advance websocket setup properties

Key Type Description
url string Data received from Topic subscription
queryParams object URL query parameters
headers object URL header parameters

ITopicQuery

Back to Interfaces

Query parameters available for a Topic

Key Type Description
topicId string
projectId string
tunnelId string
status EStatus Status of Topics
name string Topic name
size integer Size of records returned
page integer Current page number
search string Search Topic name

ITunnel

Back to Interfaces

Query parameters available for a Topic

Key Argument(s) Type Description
getTopic topicName string ITopic Get Topic instance
subscribe topicName string, identifiers string[] ITopic Subscribe to a Topic
unsubscribe topicName string boolean
publish topicName string, data ArrayBuffer, identifiers string[] void Publish messages to Topic
onReceive callback(data ITransport) void Messages received on subscription
onDisconnect callback(errorMessage IErrorMessage) void Any errors encountred
onReconnect callback(data ITransport) void Subscriptions
onErrors callback(errorMessage IErrorMessage) void Any errors encountred
disconnect void Disconnect from Tunnel

ITopic

Back to Interfaces

Query parameters available for a Topic

Key Argument(s) Type Description
addIdentifiers identifiers: INqlIdentifiers ITopic Get Topic instance
removeIdentifiers identifiers string[] ITopic Subscribe to a Topic
unsubscribe boolean
publish data ArrayBuffer, identifiers string[] void Publish messages to Topic
onReceive callback(data ITransport) void Messages received on subscription
setPresence presence string ITopic Set data specific to device

ITriggerRequest

Back to Interfaces

List of field related error, it can also contain a nested list of error

Key Type Description
topicName string Topic name that triggered this Hydration
identifiers [...{string}] List of identifiers attached to the Topic for tis Device
data string Data triggered by this Topic trigger
deviceId string UUID for the device making this request

IHydrateRequest

Back to Interfaces

Data sent to server on a Hydration request

Key Type Description
topicName string Topic name that triggered this Hydration
identifiers [...{string}] List of identifiers attached to the Topic for tis Device
deviceId string UUID for the device making this request

IErrorMessage

Back to Interfaces

Error model received from Message Broker or API

Key Type Description
id string ID for this error, can use this to find the issue
code integer HTTP code associated with this error
msg string Error message, explaining the HTTP status code received
description string Additional information attached to the error
errors [...IErrorsModel] If the error relates to field, errors, this ist will give more information on the error

IErrorsModel

Back to Interfaces

List of field related error, it can also contain a nested list of error

Key Type Description
property string Property that had the error
value string Properties current value
descriptions string What the error was on the property
errors [...IErrorsModel] or undefined

Errors

Message Broker Errors

Error Code Message Description
401 "Not authorized to use service." User validation failed.
404 "Can not find resource" Server can not find what you were looking for.
disconnect "Payload Too Large" Payload sent to message broker exceeds Message Size.

API Errors

The NoLag API uses the following error codes:

Error Code Message Description
400 "Invalid request" System does not understand request.
401 "Not authorized to use service." User validation failed.
403 "Not allowed to access resource." Not allowed to access resource.
404 "Can not find resource" Server can not find what you were looking for.
409 "Duplicate resource found" Resource already in system.
500 "System error" Something within the system has hit a error.