IoT: Send events to Azure Event Hub using Rust

IoT: Send events to Azure Event Hub using Rust

Azure Event Hub

Microsoft Azure offers a very appealing IoT service. It's called Event Hubs (https://azure.microsoft.com/en-us/services/event-hubs/). Basically it gives you and endpoint in which you can send your events. The events are stored for a retention period and can be retrieved in a FIFO manner by consumers. Each consumer, optionally, can have its own "location" so you can consume your events at different pace. The event hub, therefore, is perfect for the IoT devices as it will unburden them of the store requirement: just collect your data and send it to your event hub for later processing.

The following image depicts the architecture. As you can see the Event Hub is a declination of the Service Bus Azure service.

Rust

Rust is a - relatively - new system language that allows you to create fast applications that compile with minimal (or no) runtime. It doesn't have a garbage collector so you don't have the processing hiccups and the memory bloat typical of GCs languages. What makes it so special, compared to C/C++, is a series of features (lifetimes, borrow checker, default immutability and so on) created to ensure thread safety and memory safety. Last but not least the community is great and helpful regardless of your programming skill. You can get everything you need to start programming in Rust from here: https://www.rust-lang.org/ so don't take my word for it and start playing with Rust: it will be a rewarding experience.

Personal considerations aside, you can see how Rust is a good candidate for IoT devices: low processing power and scarce memory are constraints better handled by system languages. There are excellent blog posts on how to cross-compile Rust code to work with various IoT devices so I will not cover that point. There are also many libraries already built enabling you to interact with low level hardware (without having to ASM yourself) so you can start collecting data from your sensors with ease.

But what about sending it to Azure Event Hub?

REST

As there is no official Azure SDK for Rust yet you might wonder how to access the great functionalities without resorting to external languages (i.e. Python or C#). It turns out the Azure platform exposes most functionalities as REST endpoints. So it's just a matter to post to the right URL. Here is the documentation: https://msdn.microsoft.com/en-us/library/azure/dn790664.aspx.

The documentation tells us to POST to https://{serviceNamespace}.servicebus.windows.net/{eventHubPath}/messages with the following header:

Request Header Description
Authorization SAS token

The body will contain the event data.

With Rust is fairly easy to perform a POST request. For this example I will be using the Hyper crate. The only difficulty is how to encode the Authorization header: without it Azure will reject our events with 401 Unauthorized. The header requires a SAS token (SAS being Shared Access Signature) in a specific format.

SAS Token

This post helps us to build our SAS token: Shared Access Signature Authentication with Service Bus. Long story short we need to encode the URL and the Expiry attribute with the HMAC SHA256 based on our shared key. The server will perform the same operation (it knows the URL and the expiry attribute because we will pass them in the request) with the same key (shared) and if the result matches it will allow the request.

The following diagram depicts what we should do in detail:

Let's see how to do it in RUST code.

RUST's way to Azure Event Hub

Let's start with the transposition of above diagram. Here I will show extracts of the code. You can of course grab the complete project from GitHub (https://github.com/MindFlavor/pusheventhub) and compile try it yourself.

generate_signature

Here we use a lot of external crates. The code follows closely our diagram. Note that we are using the timestamp method of hrono::datetime::DateTime (https://lifthrasiir.github.io/rust-chrono/chrono/datetime/struct.DateTime.html) since it will give us exactly what we need: number of non-leap seconds from Jan 1st, 1970. Notice that here, for the sake of simplicity, we are initializing the Hmac each time we call the method. This is far from optimal as we should cache it and just reinitialize it with reset. You should keep that in mind if you plan to write an optimized IoT code.

submit_event

Now that we have the correct Authorization header all we need to do is to perform our request using Hyper.

Worth noting here is the event_body parameter: it is a tuple with a Reader and the expected length. You can use a struct here - it would be better - I used the tuple because I'm lazy :wink:. Also to note the expected HTTP Result code: 201 (Created). Anything else we treat as failure and send back to the caller in the AzureError enum (not shown here because boring, please refer the GitHub project for it at azure_error.rs).

Conclusion

I hope this will get started with Rust and Azure Event Hub. These two exciting technologies will allow you to start playing with the IoT world with minimum investment. But, hey, now that I've got my device data in the Event Hub what can I do? This is something for another blog post; in the meantime, check out a previous post of mine that explains how to consume Event Hub events, analyse them in a streaming manner using Stream Analytics and to generate intelligence with PowerBI: SQL Server intrusion detection using Azure Event Hub, Azure Stream Analytics and PowerBI.

Happy coding,

Francesco Cogno