We recently added a websocket endpoint in drogue cloud, to easily get a stream of events for an application, using the well-known websocket protocol. Let's have a look and build a small demo apps to consume events.

The Websocket Integration service

The service is pretty straight forward in its design : it will connect to the appropriate Kafka topic for the application and forward any new events in the websocket. The events are pushed in their Cloud-events format, as text messages.

Give it a try ! Opening a socket is as easy as :

websocat wss://websocket-integration-drogue-dev.apps.wonderful.iot-playground.org/drogue-public-temperature

Authentication

As you can see we used authentication to open the websocket. The service accepts open ID tokens, API keys and nothing/anonymous (if your app is configured for public access). Authorization requests are made with a "read" permission.

An openID token can be passed through the Authorization: Bearer header. Here using drg to get a token :

websocat wss://websocket-integration.address/yourApplication -H="Authorization: Bearer $(drg whoami -t)"

For API keys you need to use the Basic header, where the password will be the API key. The header should look like this:

Authorization: Basic base64(your-username:your-api-key)

Shared consumption

The websocket integration service is built on top of the actix actors framework which makes mutlithreading a breeze, so you can confidently open multiple connections and don't suffer any slowdowns.
To give you more flexibility, the group_id query parameter enables shared consumption. Grouping clients will result in the events split evenly between members of a group.
The url would look like this:

wss://websocket-integration.address/yourApp?group_id=myGroup

If two clients connect using "myGroup" then each will receive every other message. If you have an application generating a lot of traffic it's easy to split the load between different consumers.

Build an app !

A CLI tool is great for testing, but not an ideal base for a consuming application. Let's build a small application using rust and connect it to our websocket integration service. This example connects to a public application, so there is no need for credentials.

Now we have everything we need, let's write some code. We'll use the great tungstenite crate for the websocket functionality :

use anyhow::{anyhow, Context, Result};
use tungstenite::connect;
use tungstenite::http::{header, Request};
use url::Url;

pub fn main() -> Result<()> {
    // Here are our connection details
    let url = "wss://websocket-integration-drogue-dev.apps.wonderful.iot-playground.org";
    let application = "drogue-public-temperature";
    let url = format!("{}/{}", url, application);

    // And connect !
    let (mut socket, response) = connect(Url::parse(url).unwrap()).context("Error connecting to the Websocket endpoint:")?;
    println!("Connected to websocket");
    println!("HTTP response code: {}", response.status());

    // Now we can simply poll the connection for new messages.
    loop {
        let msg = socket.read_message();
        match msg {
            Ok(m) => {
                // ignore protocol messages, only show text
                if m.is_text() {
                    println!("{}", m.into_text().expect("Invalid message"));
                }
            }
            Err(e) => break Err(anyhow!(e)),
        }
    }
}

And voilĂ , you are streaming events in your application ! This example is pretty basic, you should get fancy and add some async and authentication in there.

In the context of a long-running application, API key are a better fit than openID tokens. To create an API key in the console, browse the API > Access keys section. You can find a buildable cargo project that shows how to use the API token authentication here.

A new tool for drg's arsenal

With the websocket service available we took the opportunity to add a stream subcommand to drg so you can quickly tap into a stream to do some debugging:

drg stream drogue-public-temperature

That's it ! If you have a default app already set in your context, then drg stream will fetch the application Id from there.

What's next ?

The next stop is to be able to send commands back to your devices using the websocket other direction. Expect to see it in a later release !