Skip to main content

Crate zbus

Crate zbus 

Source
Expand description

§zbus

This is the main subcrate of the zbus project, that provides the API to interact with D-Bus. It takes care of the establishment of a connection, the creation, sending and receiving of different kind of D-Bus messages (method calls, signals etc) for you.

Status: Stable.

§Getting Started

The best way to get started with zbus is the book, where we start with basic D-Bus concepts and explain with code samples, how zbus makes D-Bus easy.

§Wire format only

If all you need is the D-Bus wire format (the serde-based encoding that used to be the zvariant crate) and the bus name types (that used to be zbus_names), and no connection at all, disable the default features:

[dependencies]
zbus = { version = "6", default-features = false }

That build compiles zbus::wire and zbus::names and nothing else — no connection, proxy or object server. The optional wire-format features keep zvariant’s names (arrayvec, camino, chrono, heapless, option-as-array, serde_bytes, time, url, uuid), and enabling any D-Bus feature (comms, default-rt, tokio, tokio-multithread, p2p, bus-impl, proxy, service, object-manager, unixexec, ibus) brings the D-Bus API back.

zbus logs through tracing, behind the default tracing feature; a default-features = false build that wants zbus’s logs must re-enable it explicitly.

§Example code

We’ll create a simple D-Bus service and client to demonstrate the usage of zbus. Note that these examples assume that a D-Bus broker is setup on your machine and you’ve a session bus running (DBUS_SESSION_BUS_ADDRESS environment variable must be set). This is guaranteed to be the case on a typical Linux desktop session.

§Service

A simple service that politely greets whoever calls its SayHello method:

use std::{error::Error, future::pending};
use zbus::{connection, interface};

struct Greeter {
    count: u64
}

#[interface(name = "org.zbus.MyGreeter1")]
impl Greeter {
    // Can be `async` as well.
    fn say_hello(&mut self, name: &str) -> String {
        self.count += 1;
        format!("Hello {}! I have been called {} times.", name, self.count)
    }
}

// Although we use `tokio` here, you can use any async runtime of choice.
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let greeter = Greeter { count: 0 };
    let _conn = connection::Builder::session()
        .name("org.zbus.MyGreeter")
        .serve_at("/org/zbus/MyGreeter", greeter)
        .build()
        .await?;

    // Do other things or go to wait forever
    pending::<()>().await;

    Ok(())
}

You can use the following command to test it:

$ busctl --user call org.zbus.MyGreeter /org/zbus/MyGreeter org.zbus.MyGreeter1 SayHello s "Maria"
s "Hello Maria! I have been called 1 times."

§Client

Now let’s write the client-side code for MyGreeter service:

use zbus::{Connection, Result, proxy};

#[proxy(
    interface = "org.zbus.MyGreeter1",
    default_service = "org.zbus.MyGreeter",
    default_path = "/org/zbus/MyGreeter"
)]
trait MyGreeter {
    async fn say_hello(&self, name: &str) -> Result<String>;
}

// Although we use `tokio` here, you can use any async runtime of choice.
#[tokio::main]
async fn main() -> Result<()> {
    let connection = Connection::session().await?;

    // `proxy` macro creates `MyGreeterProxy` based on `MyGreeter` trait.
    let proxy = MyGreeterProxy::new(&connection).await?;
    let reply = proxy.say_hello("Maria").await?;
    println!("{reply}");

    Ok(())
}

§Synchronous programs

zbus’s API is async. A program with no async runtime of its own drives it with zbus::block_on, which runs a future to completion on the calling thread. See the FAQ of the book.

§Proxy and service API

Since zbus 6.0, the client-side proxy API and the service-side object server API live behind the proxy and service cargo features, respectively. Both are enabled by default. If you are writing a pure service or a pure client, you can disable the API you don’t need to reduce the size of your binary.

The service side of the standard org.freedesktop.DBus.ObjectManager interface, fdo::ObjectManager, is behind the object-manager feature, which builds on service and is also enabled by default.

§Compatibility with async runtimes

zbus is runtime-agnostic. A program with no async runtime of its own drives it with zbus::block_on; see the FAQ. A program built on Tokio turns on the tokio feature, and a connection built while a Tokio runtime is current runs on it, with no extra thread of zbus’s own. Any other executor can use the default zruntime backend as it is, with no integration needed: a connection built outside a zbus::block_on call is simply run by that backend’s own helper thread. connection::Builder::runtime is there for an application that wants to hand a connection a runtime of its own instead — any implementation of runtime::traits::Runtime, which documents the full contract, the connects and the helper process of a unixexec: address included, and spawn_blocking, the one method with a default, which the handful of calls with no async form go through — not something every other executor needs.

zbus’s async locks come from zruntime; a build on zruntime or an external runtime needs no lock feature and pulls in no lock crate for them. A Tokio build uses Tokio’s locks instead.

zbus::block_on over a runtime of your own only works while that runtime’s loop runs on another thread. A call made from the loop’s own thread deadlocks: it waits on a connection that only makes progress while the loop it just stopped runs.

§Special tokio support

Enabling the tokio feature puts a connection on your tokio runtime instead of the default zruntime backend, with no thread of zbus’s own:

# Sample Cargo.toml snippet.
[dependencies]
zbus = { version = "6", features = ["tokio"] }

The tokio and default-rt features are additive: with both enabled, zbus picks Tokio when a Tokio runtime is current on the thread that builds the connection, and zruntime otherwise. With only tokio (no default-rt), a connection must be built from a thread running a Tokio runtime. To leave the zruntime backend out of the build, disable default features and list what you use instead, e.g. default-features = false, features = ["tokio", "proxy", "service"]. The zruntime crate stays in the dependency tree for the Event and broadcast channels zbus’s own types build on, but none of its runtime is built.

A program with no async runtime of its own drives the API from inside zbus::block_on, which with the tokio feature polls the future on a Tokio runtime of its own, so a connection built inside that call always runs on tokio when that feature is on. That runtime is single-threaded: the connection’s work only runs while a thread is inside zbus::block_on. Enable the tokio-multithread feature (which enables tokio) to make it a multi-threaded runtime instead, whose worker threads keep the connection going in between calls.

Note: On Windows, a connection that ends up on Tokio cannot use a Unix domain socket, even when the default-rt feature is also on; see the corresponding tokio issue on GitHub.

§WASI

zbus builds for WASI, wasm32-wasip1 and wasm32-wasip2, on the default zruntime backend, on Tokio (whose sockets need RUSTFLAGS="--cfg tokio_unstable" there) and on a runtime of your own. WASI has no Unix domain sockets, no threads and no processes, so there:

  • A connection goes over a TCP socket: to a tcp: address, which needs wasm32-wasip2 and a host that grants the network, or over a socket the host hands the program, as a std::net::TcpStream made from its descriptor and given to connection::Builder::tcp_stream. That socket may well be a Unix domain one on the host’s side, connected to the bus: then authenticate with AuthMechanism::External, and give connection::Builder::user_id the ID of the user the bus knows the host as, as WASI has no user ID of its own.
  • Address::session and Address::system have no default to fall back to, so they need DBUS_SESSION_BUS_ADDRESS and DBUS_SYSTEM_BUS_ADDRESS to be set.
  • No helper thread runs a connection while no thread is inside zbus::block_on, or inside the block_on of the Tokio runtime it is on: its work, the delivery of signals included, waits for the next call. Blocking work, such as resolving a host name, blocks the program’s one thread.

Re-exports§

pub use address::Address;
pub use message::Message;
pub use connection as conn;
pub use connection::Connection;
pub use runtime::AsyncDrop;
pub use match_rule::MatchRule;
pub use match_rule::OwnedMatchRule;
pub use proxy::Proxy;
pub use object_server::ObjectServer;

Modules§

address
D-Bus address handling.
as_variant
Utilities to (de)serialize a value as a zbus::Variant.
connection
Connection API.
fdo
The standard D-Bus interfaces.
match_rule
Bus match rule API.
message
D-Bus Message.
names
Types for the various D-Bus bus names.
object_server
The object server API.
proxy
The client-side proxy API.
runtime
Integration with the async runtime that drives a connection.
wire
The D-Bus wire format.
zvariantDeprecated
Deprecated aliases for the wire module.

Macros§

signature
Constructs a const Signature with compile-time validation.

Structs§

Array
A helper type to wrap arrays in a Variant.
Dict
A helper type to wrap dictionaries in a Variant.
DynamicTuple
A helper type to serialize or deserialize a tuple whose elements implement DynamicType but not Type.
FilePath
File name represented as a nul-terminated byte array.
Guid
A D-Bus server GUID.
MessageStream
A stream::Stream implementation that yields Message items.
ObjectPath
String that identifies objects at a given destination on the D-Bus bus.
Optional
An optional value.
OwnedFd
A file-descriptor type wrapper.
OwnedGuid
Owned version of Guid.
OwnedObjectPath
Owned ObjectPath
OwnedStructure
Owned Structure
OwnedVariant
Owned Variant
Str
This type is used for keeping strings in a Variant, among other things.
Structure
A helper type to wrap structs in Variant.

Enums§

Error
The error type for zbus.
Fd
A file-descriptor type wrapper.
MaxDepthExceeded
Enum representing the max depth exceeded error.
Signature
A D-Bus signature in parsed form.
Variant
A generic container, in the form of an enum that holds exactly one value of any of the other types.

Traits§

Basic
Trait for basic types.
DBusError
A trait that needs to be implemented by error types to be returned from D-Bus methods.
DynamicType
Types with dynamic signatures.
NoneValue
Type that uses a special value to be used as none.
Type
Trait implemented by all serializable types.

Functions§

block_on
Runs a future to completion, blocking the calling thread until it is done.

Type Aliases§

BoxDBusError
A DBusError of any concrete type.
Result
Alias for a Result with the error type zbus::Error.

Attribute Macros§

interface
Attribute macro for implementing a D-Bus interface.
proxy
Attribute macro for defining D-Bus proxies (using zbus::Proxy).

Derive Macros§

DBusError
Derive macro for implementing zbus::DBusError trait.
DeserializeDict
Adds Deserialize implementation to structs to be deserialized from a D-Bus dictionary type.
OwnedVariant
Implements conversions for your type to/from OwnedVariant.
SerializeDict
Adds Serialize implementation to structs to be serialized as a D-Bus dictionary type.
Type
Derive macro to add Type implementation to structs and enums.
Variant
Implements conversions for your type to/from Variant.