Skip to content

WebSocket Server

The WebSocket server (WSS) is a microservice dedicated to sending real time data to various clients through a WebSocket (WS). It is a distinct service from the Management API.

Rooms and namespaces

Socket.IO uses the notions of rooms and namespaces to simplify the dispatching of data to all clients. Note that the rooms are a server-side only notion: clients are not aware that they are sent to a room. But they are aware that they are joining a namespace.

Note

For more information on Socket.IO, consult its official get started guide. This documentation will not cover the technical details of Socket.IO, but will focus on its usage to retrieve real-time data from Kamea.

In the Kamea WSS, namespaces are used to distinguish higher-level types : devices, jobs, etc... Currently, the only supported namespace is the devices one.

Clients must join a specific namespace when they connect to the WSS. This is done differently based on the used client library. For example, when using the JavaScript / TypeScript one, the namespace is provided in the URL. If the WSS is available on the domain sample.kamea.com, and we want to connect to the devices namespace, the initialization would look like that:

const { io } = require("socket.io-client");

const socket = io("https://sample.kamea.com/devices");

Note

All further code examples in this file will use the same client library

In each namespace, rooms will be used depending on the data type. For instance, in the devices namespace, one room will be created by device, and will be strictly dedicated to dispatching the telemetries of this single device. Those rooms are named telemetries:<the_device_id>

Client subscription

To subscribe to real time telemetries, clients must send a subscription request to the WSS. The request payload depends on the type of requested data. But in all cases, the user must provide its bearer token after having previously retrieved it from the identity provider.

Example:

const accessToken = <token>;
const wssUrl = "https://sample.kamea.com/devices";

const socket = io(wssUrl, {
    extraHeaders: {
        Authorization: `Bearer ${accessToken}`,
    },
});

After initializing the connection like that, the Authorization header will be sent with each client subscription request.

Once the client is connected, the WSS will send the connect event. The client should listen to it to know when it can subscribe.

Example:

socket.on("connect", () => {
    console.log("Connected");
});

Then, to send a subscription, the client must send a message to the WSS, with the event matching the expected data, and a payload specific to the data type.

Example: To subscribe to real time telemetries, send a message with this format

socket.on("connect", () => {
    socket.emit("telemetries", {
        deviceId: "C5C80676-890C-4024-A16F-DF81AB0B5A22",
        tenantId: "12B80A37-D30E-49F1-AF3B-356ECC1AD96C",
    });
});

When receiving this message, the WSS will validate the user's token, and send them to the according room. Then, every time data is sent to this room, the user will be notified.

Note

For a complete description of all the possible WSS messages, check its AsyncAPI documentation. Its available on the /doc endpoint on the WSS. So, to keep using the previous example, it would be available on https://sample.kamea.com/doc.

Note that the AsyncAPI documentation is written from the client point of view. Which means that for operations noted as PUB, the client must send a message. For operations noted as SUB, the client will receive messages. In both cases, the message format, whether it comes from the client or the server, is documented the same way.

Authorization

The WSS does not validate the user's authorization by itself. Instead, it calls the API /authorization/check-authorized endpoint.

If the user is not authorized on the requested resource, an access_denied message will be sent, and the connection will be forcefully closed from the server.

Example:

socket.on("access_denied", () => {
    console.log("Access denied.");
});

Errors

WebSockets can be quite error prone when working with it for the first time, especially when it comes to initiating the connection with the server. When it fail, Socket.IO will send a connect_error message, with the reason. It is advised to listen to this event to understand why the connection failed:

socket.on("connect_error", () => {
    console.log(`connect_error: ${err}`);
});

Note that this message is sent by the client library, because it means that the server did not receive the request. Frequent error causes are CORS issues, or invalid namespace.

Upon unexpected error, the WSS will send an internal_server_error message, with a message when possible. This issue can happen if the Management API is unavailable. In that case, start by checking that it is currently running and accessible to the WSS.