CloudAMQP with MQTT and Rust
We recommend rumqttc,
the most widely used MQTT client for Rust. The examples use its blocking
client; AsyncClient works the same way on Tokio.
cargo add rumqttc
Publish and subscribe
Set MQTT_HOST, MQTT_PORT, MQTT_USERNAME and MQTT_PASSWORD to the MQTT
details on your instance’s details page in the CloudAMQP console. Port 8883
uses TLS. Without them, the examples connect to a local broker.
Save the publisher as src/bin/publisher.rs:
use std::env;
use rumqttc::{Client, Event, MqttOptions, Packet, QoS, Transport};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let host = env::var("MQTT_HOST").unwrap_or("localhost".into());
let port = env::var("MQTT_PORT").unwrap_or("1883".into()).parse()?;
let mut options = MqttOptions::new(format!("publisher-{}", std::process::id()), host, port);
options.set_credentials(
env::var("MQTT_USERNAME").unwrap_or("guest".into()),
env::var("MQTT_PASSWORD").unwrap_or("guest".into()),
);
if port == 8883 {
options.set_transport(Transport::tls_with_default_config());
}
let (client, mut connection) = Client::new(options, 10);
client.publish("hello", QoS::AtLeastOnce, false, "Hello world!")?;
// The connection sends the message; QoS 1 waits for the broker's PUBACK
for event in connection.iter() {
if let Event::Incoming(Packet::PubAck(_)) = event? {
println!(" [x] Sent 'Hello world!'");
break;
}
}
client.disconnect()?;
Ok(())
}
Save the subscriber as src/bin/worker.rs:
use std::env;
use rumqttc::{Client, Event, MqttOptions, Packet, QoS, Transport};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let host = env::var("MQTT_HOST").unwrap_or("localhost".into());
let port = env::var("MQTT_PORT").unwrap_or("1883".into()).parse()?;
let mut options = MqttOptions::new(format!("worker-{}", std::process::id()), host, port);
options.set_credentials(
env::var("MQTT_USERNAME").unwrap_or("guest".into()),
env::var("MQTT_PASSWORD").unwrap_or("guest".into()),
);
if port == 8883 {
options.set_transport(Transport::tls_with_default_config());
}
let (client, mut connection) = Client::new(options, 10);
client.subscribe("hello", QoS::AtLeastOnce)?;
// rumqttc acks each QoS 1 message as it arrives
for event in connection.iter() {
match event? {
Event::Incoming(Packet::SubAck(_)) => {
println!(" [*] Waiting for messages. To exit press CTRL+C")
}
Event::Incoming(Packet::Publish(message)) => {
println!(
" [x] Received '{}'",
String::from_utf8_lossy(&message.payload)
)
}
_ => {}
}
}
Ok(())
}
Run cargo run --bin worker in one terminal and cargo run --bin publisher in
another.
A runnable example is in rust/rumqttc in cloudamqp/examples.
Good to know
- Put the vhost in the username, as
vhost:user. MQTT has no vhost of its own, and the console shows the username that way. Transport::tls_with_default_config()turns on TLS, verified against the system’s certificates with rustls.- Iterate the connection. Nothing is sent or received until you poll
connection.iter(); the publisher polls it until the broker’s PUBACK arrives. - Messages are acked as they arrive. rumqttc acks each QoS 1 message before
the loop sees it; set
set_manual_acks(true)to ack after processing.