Async Runtime Support
nmrs is built on async Rust and uses zbus for D-Bus communication. While the examples in this book use Tokio, nmrs works with any async runtime.
Tokio (Recommended)
Tokio is the most commonly used runtime and the one used in all examples:
use nmrs::NetworkManager; #[tokio::main] async fn main() -> nmrs::Result<()> { let nm = NetworkManager::new().await?; let networks = nm.list_networks().await?; println!("{} networks found", networks.len()); Ok(()) }
Add to your Cargo.toml:
[dependencies]
nmrs = "2.2"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Single-Threaded Tokio
For lightweight applications, you can use the current-thread runtime:
#[tokio::main(flavor = "current_thread")] async fn main() -> nmrs::Result<()> { let nm = nmrs::NetworkManager::new().await?; // ... Ok(()) }
This is what nmrs-gui uses internally.
async-std
use nmrs::NetworkManager; #[async_std::main] async fn main() -> nmrs::Result<()> { let nm = NetworkManager::new().await?; let networks = nm.list_networks().await?; println!("{} networks found", networks.len()); Ok(()) }
[dependencies]
nmrs = "2.2"
async-std = { version = "1", features = ["attributes"] }
smol
use nmrs::NetworkManager; fn main() -> nmrs::Result<()> { smol::block_on(async { let nm = NetworkManager::new().await?; let networks = nm.list_networks().await?; println!("{} networks found", networks.len()); Ok(()) }) }
[dependencies]
nmrs = "2.2"
smol = "2"
GLib/GTK (for GUI applications)
When building GTK4 applications, use the GLib main context:
#![allow(unused)] fn main() { use nmrs::NetworkManager; // Inside a GTK application's async context glib::MainContext::default().spawn_local(async { let nm = NetworkManager::new().await.unwrap(); let networks = nm.list_networks().await.unwrap(); for net in &networks { println!("{}: {}%", net.ssid, net.strength.unwrap_or(0)); } }); }
This is how nmrs-gui integrates nmrs into its GTK4 interface.
How It Works
nmrs uses zbus for D-Bus communication, which itself uses an internal async runtime. When you call NetworkManager::new().await, zbus establishes a connection to the system D-Bus. This connection is runtime-agnostic — zbus handles the async I/O internally.
The NetworkManager struct is Clone and Send, so you can share it across tasks regardless of which runtime you use.
Thread Safety
NetworkManager is:
Clone— clones share the same D-Bus connection (cheap)Send— can be moved across threadsSync— can be shared viaArc(thoughCloneis usually simpler)
However, concurrent connection operations are not supported. Don't call connect() from multiple tasks simultaneously. Use is_connecting() to check if a connection is in progress.
Next Steps
- Custom Timeouts – configure operation timeouts
- D-Bus Architecture – understand the D-Bus layer