Rust API & SDK Docs 0.6.0

This guide walks you through a simple "Hello, World" application that demonstrates the core concepts of PubNub:

  • Setting up a connection
  • Sending messages
  • Receiving messages in real-time

Overview

This guide will help you get up and running with PubNub in your Rust application. Since Rust is commonly used across different platforms, we provide two implementation paths:

  • Server-side applications: For developers building backend services and applications with Rust
  • Embedded systems: For developers using Rust in resource-constrained environments (embedded devices, WebAssembly)

The core PubNub concepts and API usage remain the same across both paths, but implementation details like feature selection and memory management differ. Select the appropriate tab in each section to see platform-specific guidance.

Feature selection

The Rust SDK is designed to be modular with support for different feature sets. You can enable or disable specific features based on your needs, which is especially useful for embedded systems with limited resources.

Prerequisites

Before we dive in, make sure you have:

  • A basic understanding of Rust
  • Rust and Cargo installed on your system
  • A PubNub account (we'll help you set this up!)

Setup

Get your PubNub keys

First things first – you'll need your PubNub keys to get started. Here's how to get them:

  • Sign in or create an account on the PubNub Admin Portal
  • Create an app (or use an existing one)
  • Find your publish and subscribe keys in the app dashboard

When you create a new app, PubNub automatically generates your first set of keys. While you can use the same keys for development and production, we recommend creating separate keysets for each environment for better security and management.

Install the SDK

SDK version

Always use the latest SDK version to have access to the newest features and avoid security vulnerabilities, bugs, and performance issues.

Add pubnub to your Rust project in the Cargo.toml file:

1[dependencies]
2pubnub = "0.6.0"
3serde = "1.0"
4serde_json = "1.0"
5tokio = { version = "1", features = ["full"] }

Then in your main.rs file:

1use pubnub::dx::*;
2use pubnub::core::*;
3use serde_json::json;
4
5#[tokio::main]
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7 // Set up PubNub configuration
8 let pubnub = PubNubClientBuilder::with_reqwest_transport()
9 .with_keyset(Keyset {
10 subscribe_key: "demo", // Replace with your subscribe key
11 publish_key: Some("demo"), // Replace with your publish key
12 secret_key: None,
13 })
14 .with_user_id("rust-server-user")
15 .build()?;
show all 22 lines

Source code

Clone the GitHub repository:

1git clone https://github.com/pubnub/rust

Steps

Initialize PubNub

In your Rust project, create a new file (e.g., main.rs) with the following content. This is the minimum configuration you need to send messages with PubNub.

Make sure to replace the placeholder keys with your publish and subscribe keys from the Admin Portal.

1use pubnub::dx::*;
2use pubnub::core::*;
3use serde_json::json;
4
5#[tokio::main]
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7 // Set up PubNub configuration
8 let pubnub = PubNubClientBuilder::with_reqwest_transport()
9 .with_keyset(Keyset {
10 subscribe_key: "demo", // Replace with your subscribe key
11 publish_key: Some("demo"), // Replace with your publish key
12 secret_key: None,
13 })
14 .with_user_id("rust-server-user")
15 .build()?;
show all 22 lines

For more information, refer to the Configuration section of the SDK documentation.

Set up event listeners

Listeners help your app react to events and messages. You can implement custom app logic to respond to each type of message or event.

Using Rust's async streams makes it easy to process events as they arrive:

1// Import required event handling traits
2use pubnub::dx::subscribe::Update;
3use pubnub::subscribe::{Subscriber, EventSubscriber};
4use futures::StreamExt;
5
6// Listen for client status changes
7tokio::spawn(pubnub.status_stream().for_each(|status| async move {
8 println!("\nStatus: {:?}", status)
9}));
10
11// Listen for all subscription events
12tokio::spawn(subscription.stream().for_each(|event| async move {
13 match event {
14 Update::Message(message) | Update::Signal(message) => {
15 // Process incoming messages
show all 35 lines

If you only want to listen for specific events, you can use specialized streams:

1// Only listen for message events on a specific channel
2tokio::spawn(
3 channel_subscription
4 .messages_stream()
5 .for_each(|message| async move {
6 if let Ok(utf8_message) = String::from_utf8(message.data.clone()) {
7 if let Ok(cleaned) = serde_json::from_str::<String>(&utf8_message) {
8 println!("Message received: {}", cleaned);
9 }
10 }
11 })
12);

For more information, refer to the Event Listeners section of the SDK documentation.

Create a subscription

To receive messages sent to a particular channel, you need to subscribe to it. This setup allows you to receive real-time updates whenever anyone publishes to that channel.

Create a subscription to one or more channels using the subscription parameters:

1use pubnub::subscribe::SubscriptionParams;
2
3// Subscribe to a single channel
4let subscription = pubnub.subscription(SubscriptionParams {
5 channels: Some(&["my_channel"]),
6 channel_groups: None,
7 options: None
8});
9
10// Or create a subscription from a channel entity
11let channel = pubnub.channel("my_channel");
12let channel_subscription = channel.subscription(None);
13
14// Activate the subscriptions
15subscription.subscribe();
show all 18 lines

For more information, refer to the Subscribe section of the SDK documentation.

Publish messages

When you publish a message to a channel, PubNub delivers that message to everyone who is subscribed to that channel. A message can be any type of JavaScript Object Notation (JSON)-serializable data smaller than 32 KiB.

Let's publish a message to our channel:

1// Wait a moment for the subscription to establish
2tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
3
4// Send a message to the channel
5match pubnub
6 .publish_message("hello world!")
7 .channel("my_channel")
8 .r#type("text-message") // Optional: specify a message type
9 .execute()
10 .await {
11 Ok(result) => {
12 println!("Message published successfully! Timetoken: {}", result.timetoken);
13 }
14 Err(err) => {
15 println!("Failed to publish message: {:?}", err);
show all 17 lines

Clean up resources

When your application is shutting down or a component using PubNub is being removed, it's important to properly clean up resources to avoid memory leaks and ensure network connections are closed gracefully.

To properly clean up resources, unsubscribe from channels and remove listeners:

1// Unsubscribe from the channel
2subscription.unsubscribe();
3
4// Remove listeners to avoid memory leaks
5pubnub.remove_all_listeners();
6
7// For more thorough cleanup, you can also destroy the client
8// which will unsubscribe from all channels and remove all listeners
9pubnub.destroy();
10
11println!("Cleaned up PubNub resources");

This is particularly important in long-running applications that may create and dispose of multiple PubNub clients or subscriptions.

Run the app

To run your application:

  1. Make sure all the code is in your main.rs file.
  2. Run it with cargo run in your terminal.

If you're using async code, make sure your Cargo.toml includes tokio:

1[dependencies]
2pubnub = "0.6.0"
3serde = "1.0"
4serde_json = "1.0"
5tokio = { version = "1", features = ["full"] }

And your main function should have the tokio runtime attribute:

1#[tokio::main]
2async fn main() -> Result<(), Box<dyn std::error::Error>> {
3 // Your code here
4 Ok(())
5}

When you run the application, you should see output similar to the following:

1PubNub client initialized successfully!
2Subscribed to channel: my_channel
3Connected to PubNub network
4Message published successfully! Timetoken: 16967543908123456
5Received message on channel 'my_channel': {"text":"Hello, world!","sender":"Rust Server"}
6Global listener: Received message on channel 'my_channel': {"text":"Hello, world!","sender":"Rust Server"}

Complete example

Here's the complete working example that puts everything together:

1use pubnub::subscribe::Subscriber;
2use futures::StreamExt;
3use tokio::time::sleep;
4use std::time::Duration;
5use serde_json;
6use pubnub::{
7 dx::subscribe::Update,
8 subscribe::{EventSubscriber, EventEmitter, SubscriptionParams},
9 Keyset, PubNubClientBuilder,
10};
11
12#[tokio::main]
13async fn main() -> Result<(), Box<dyn std::error::Error>> {
14 // Set up PubNub configuration
15 let publish_key = "demo"; // Replace with your publish key
show all 117 lines

Troubleshooting

If you don't see the expected output, here are some common issues and how to fix them:

IssuePossible Solutions
No connection message
  • Check your internet connection.
  • Verify your publish and subscribe keys are correct.
  • Make sure you're not behind a firewall blocking PubNub's connections.
Message not received
  • Double-check that you're subscribed to the correct channel.
  • Verify that the message was actually sent (check for any error messages).
  • Make sure you're waiting long enough for the message to be delivered.
Build errors
  • Ensure you've added the PubNub dependency correctly.
  • Check that you're using a compatible version of Rust (1.65.0+ is recommended).
  • Make sure all imports are correct.
Runtime errors
  • If using async code, ensure you've set up the tokio runtime correctly.
  • Make sure you're handling errors properly with proper match statements or the ? operator.

Next steps

Great job! 🎉 You've successfully created your first PubNub application with Rust. Here are some exciting things you can explore next:

Last updated on