A Rust API for D-Bus communication.

Related tags

Miscellaneous zbus
Overview

pipeline status

zbus

A Rust API for D-Bus communication. The goal is to provide a safe and simple high- and low-level API akin to GDBus, that doesn't depend on C libraries.

The project is divided into three main crates:

zbus

The zbus crate provides the main API you will use to interact with D-Bus from Rust. 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.

zbus crate is currently Linux-specific1.

Status: Stable2.

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.

Example code

Client

This code display a notification on your Freedesktop.org-compatible OS:

>, expire_timeout: i32, ) -> zbus::Result ; } // Although we use `async-std` here, you can use any async runtime of choice. #[async_std::main] async fn main() -> Result<(), Box > { let connection = Connection::session().await?; // `dbus_proxy` macro creates `NotificationProxy` based on `Notifications` trait. let proxy = NotificationsProxy::new(&connection).await?; let reply = proxy.notify( "my-app", 0, "dialog-information", "A summary", "Some body", &[], &HashMap::new(), 5000, ).await?; dbg!(reply); Ok(()) } ">
use std::{collections::HashMap, error::Error};

use zbus::{Connection, dbus_proxy};
use zvariant::Value;

#[dbus_proxy(
    interface = "org.freedesktop.Notifications",
    default_service = "org.freedesktop.Notifications",
    default_path = "/org/freedesktop/Notifications"
)]
trait Notifications {
    fn notify(
        &self,
        app_name: &str,
        replaces_id: u32,
        app_icon: &str,
        summary: &str,
        body: &str,
        actions: &[&str],
        hints: &HashMap<&str, &Value<'_>>,
        expire_timeout: i32,
    ) -> zbus::Result<u32>;
}

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

    // `dbus_proxy` macro creates `NotificationProxy` based on `Notifications` trait.
    let proxy = NotificationsProxy::new(&connection).await?;
    let reply = proxy.notify(
        "my-app",
        0,
        "dialog-information",
        "A summary",
        "Some body",
        &[],
        &HashMap::new(),
        5000,
    ).await?;
    dbg!(reply);

    Ok(())
}

Server

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

String { self.count += 1; format!("Hello {}! I have been called: {}", name, self.count) } } // Although we use `async-std` here, you can use any async runtime of choice. #[async_std::main] async fn main() -> Result<(), Box > { let greeter = Greeter { count: 0 }; let _ = ConnectionBuilder::session()? .name("org.zbus.MyGreeter")? .serve_at("/org/zbus/MyGreeter", greeter)? .build() .await?; // Do other things or go to sleep. sleep(Duration::from_secs(60)); Ok(()) } ">
use std::{
    error::Error,
    thread::sleep,
    time::Duration,
};
use zbus::{ObjectServer, ConnectionBuilder, dbus_interface, fdo};

struct Greeter {
    count: u64
}

#[dbus_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: {}", name, self.count)
    }
}

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

    // Do other things or go to sleep.
    sleep(Duration::from_secs(60));

    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"
Hello Maria!
s

Blocking API

While zbus is primarily asynchronous (since 2.0), blocking wrappers are provided for convenience.

Compatibility with async runtimes

zbus is runtime-agnostic and should work out of the box with different Rust async runtimes. However, in order to achieve that, zbus spawns a thread per connection to handle various internal tasks. If that is something you would like to avoid, you need to:

zvariant

This crate provides API for encoding/decoding of data to/from D-Bus wire format. This binary wire format is simple and very efficient and hence useful outside of D-Bus context as well. A modified form of this format, GVariant is very commonly used for efficient storage of arbitrary data and is also supported by this crate.

Status: Stable.

Example code

= from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, v); // Dictionary let mut map: HashMap = HashMap::new(); map.insert(1, "123"); map.insert(2, "456"); let encoded = to_bytes(ctxt, &map).unwrap(); let decoded: HashMap = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded[&1], "123"); assert_eq!(decoded[&2], "456"); ">
use std::collections::HashMap;
use byteorder::LE;
use zvariant::{from_slice, to_bytes};
use zvariant::EncodingContext as Context;

// All serialization and deserialization API, needs a context.
let ctxt = Context::<LE>::new_dbus(0);
// You can also use the more efficient GVariant format:
// let ctxt = Context::
     
      ::new_gvariant(0);
     

// i16
let encoded = to_bytes(ctxt, &42i16).unwrap();
let decoded: i16 = from_slice(&encoded, ctxt).unwrap();
assert_eq!(decoded, 42);

// strings
let encoded = to_bytes(ctxt, &"hello").unwrap();
let decoded: &str = from_slice(&encoded, ctxt).unwrap();
assert_eq!(decoded, "hello");

// tuples
let t = ("hello", 42i32, true);
let encoded = to_bytes(ctxt, &t).unwrap();
let decoded: (&str, i32, bool) = from_slice(&encoded, ctxt).unwrap();
assert_eq!(decoded, t);

// Vec
let v = vec!["hello", "world!"];
let encoded = to_bytes(ctxt, &v).unwrap();
let decoded: Vec<&str> = from_slice(&encoded, ctxt).unwrap();
assert_eq!(decoded, v);

// Dictionary
let mut map: HashMap<i64, &str> = HashMap::new();
map.insert(1, "123");
map.insert(2, "456");
let encoded = to_bytes(ctxt, &map).unwrap();
let decoded: HashMap<i64, &str> = from_slice(&encoded, ctxt).unwrap();
assert_eq!(decoded[&1], "123");
assert_eq!(decoded[&2], "456");

zvariant_derive

This crate provides a derive macro to easily implement Type trait on structs and enums.

Status: Stable.

Example code

::new_dbus(0); let encoded = to_bytes(ctxt, &s).unwrap(); let decoded: Struct = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, s); ">
use zvariant::{EncodingContext, from_slice, to_bytes};
use zvariant::{derive::Type, Type};
use serde::{Deserialize, Serialize};
use byteorder::LE;

#[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
struct Struct<'s> {
    field1: u16,
    field2: i64,
    field3: &'s str,
}

assert_eq!(Struct::signature(), "(qxs)");
let s = Struct {
    field1: 42,
    field2: i64::max_value(),
    field3: "hello",
};
let ctxt = EncodingContext::<LE>::new_dbus(0);
let encoded = to_bytes(ctxt, &s).unwrap();
let decoded: Struct = from_slice(&encoded, ctxt).unwrap();
assert_eq!(decoded, s);

Other crates

Apart from the three crates described above, zbus project also provides a few other crates:

zbus_macros

This crate provides the convenient zbus macros that we already saw in action in the sample code above. However, zbus crate re-exports the macros for your convenience so you do not need to use this crate directly.

Status: Stable.

zbus_polkit

A crate to interact with PolicyKit, a toolkit for defining and handling authorizations. It is used for allowing unprivileged processes to speak to privileged processes.

Status: Stable.

Example code

use zbus::Connection;
use zbus_polkit::policykit1::*;

// Although we use `async-std` here, you can use any async runtime of choice.
#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let connection = Connection::system().await?;
    let proxy = AuthorityProxy::new(&connection).await?;
    let subject = Subject::new_for_owner(std::process::id(), None, None)?;
    let result = proxy.check_authorization(
        &subject,
        "org.zbus.BeAwesome",
        &std::collections::HashMap::new(),
        CheckAuthorizationFlags::AllowUserInteraction.into(),
        "",
    ).await?;

    Ok(())
}

zbus_xmlgen

A binary crate that provides a developer tool to generate Rust code from D-Bus XML interface descriptions. It can be used to generate the code directly from a running D-Bus system, session or other service, or using a preexisting XML file for input.

Status: Stable.

Usage

$ cargo install zbus_xmlgen
$ zbus-xmlgen --system org.freedesktop.login1 /org/freedesktop/login1
$ zbus-xmlgen --session org.freedesktop.ScreenSaver /org/freedesktop/ScreenSaver
$ zbus-xmlgen --address unix:abstract=/home/user/.cache/ibus/dbus-fpxKwgbJ org.freedesktop.IBus /org/freedesktop/IBus
$ zbus-xmlgen interface.xml

zbus_names

This crate provides collection of types for various D-Bus bus names.

This is used by zbus (and in future by zbus_macros as well) crate. Other D-Bus crates are also encouraged to use this API in the spirit of cooperation. :)

Status: Stable.

Getting Help

If you need help in using these crates, are looking for ways to contribute, or just want to hang out with the cool kids, please come chat with us in the #zbus:matrix.org Matrix room. If something doesn't seem right, please file an issue.

Portability

All crates are currently Unix-only and will fail to build on non-unix. This is hopefully a temporary limitation. Moreover, integration tests of zbus crate currently require a session bus running on the build host.

License

MIT license LICENSE-MIT

Footnotes

  1. Support for other OS exist, but it is not supported to the same extent. D-Bus clients in javascript (running from any browser) do exist though. And zbus may also be working from the browser sometime in the future too, thanks to Rust 🦀 and WebAssembly 🕸 . ↩

  2. We might have to change the API but zbus follows semver convention so your code won't just break out of the blue. Just make sure you depend on a specific major version of zbus. ↩

You might also like...
A gui api explorer written in Rust.

Zzz - GUI Api platform Pronounced "Zees"; as in "catching some Z's". A pun on RESTful APIs. example URL: https://jsonplaceholder.typicode.com/todos/ T

Rust bindings for the Mattermost API

mattermost_api Rust bindings for the Mattermost API Installing Add the latest version to your Cargo.toml. Using Docs link. Developing Building Require

A Rust wrapper for the SponsorBlock API.

sponsor-block A Rust wrapper for the SponsorBlock API, which you can find complete documentation for here. Uses SponsorBlock data licensed under CC BY

A powerful minecraft bedrock software written in Rust with a powerful Typescript plugin API.
A powerful minecraft bedrock software written in Rust with a powerful Typescript plugin API.

Netrex A powerful minecraft bedrock software written in RustLang. Why Netrex? It's written in Rust. Unique and straight to the point. Typescript Plugi

Wrapper library for utilizing DigitalOcean API v2 in Rust

doapi-rs Wrapper library for utilizing DigitalOcean API v2 in Rust Disclaimer This library is in alpha - it may do anything up to, and including, eati

A high-level Rust crate around the Discord API, aimed to be easy and straight-forward to use.
A high-level Rust crate around the Discord API, aimed to be easy and straight-forward to use.

rs-cord A high-level Rust crate around the Discord API, aimed to be easy and straight-forward to use. Documentation • Crates.io • Discord Navigation M

Serenity is a Rust library for the Discord API
Serenity is a Rust library for the Discord API

serenity Serenity is a Rust library for the Discord API. View the examples on how to make and structure a bot. Serenity supports bot login via the use

A backend API starter with Rust & postgres

Rust backend starter Rust backend starter with OpenAPI spec & swagger with rocket_okapi

The easiest way to use BotiCord API in Rust
The easiest way to use BotiCord API in Rust

The easiest way to use BotiCord API in Rust · Docs Usage [dependencies]

Comments
  •  None of you are engineers, and you'll never even be close.

    None of you are engineers, and you'll never even be close.

    Michael, you are not an engineer, never were, and never will be close to one.

    @mmstick Stop making lies about real Engineering. Engineering has nothing to do with sitting behind a keyboard and writing code. There is no such thing as "desktop" "engineer". Thats the stupidest and most pathetic lie ever.

    Engineering is a real subject. Engineering means designing and building real mechanical systems, like vehicular engines and turbojets. Software devs have absolutely nothing to do with engineering, and they are being stupid wannabe liars. They will never be engineers, in fact, they don't even know what it takes to be an engineer. None of you are engineers, and you'll never even be close. So stop being disrespectful to real engineers (mechanical engineering is real engineering, and nothing else).

    opened by ghost 1
Owner
Michael Murphy
System76 engineer; Linux developer; Rust programmer
Michael Murphy
API wrapper for the tankerkönig api

tankerkoenig-rs API wrapper for the tankerkoenig-api written in rust. Gives you ready deserialized structs and a easy to use and strictly typed api. I

Jonathan 2 Feb 27, 2022
A repository full of manually generated hand curated JSON files, which contain the API Types that the Discord API returns.

Discord API Types A repository full of manually generated hand curated JSON files, which contain the API Types that the Discord API returns. Also did

Unofficial Discord Documentation 1 Sep 16, 2022
Notion Offical API client library for rust

Notion API client library for rust.

Jake Swenson 65 Dec 26, 2022
Rust lib for Scaleway API

Notes This Scaleway API Crate is created and maintained by Qovery and used in production in the Qovery Engine. This project relies on OpenAPI Generato

Qovery 5 Nov 10, 2022
The official rust implementation of the SpamProtectionBot API

SpamProtection-rs Table of contents About Supported Rust version Features How to use Credits License About SpamProtection-Rust is a Rust wrapper for I

Intellivoid 0 Feb 26, 2022
An asynchronous Rust client library for the Hashicorp Vault API

vaultrs An asynchronous Rust client library for the Hashicorp Vault API The following features are currently supported: Auth AppRole JWT/OIDC Token Us

Joshua Gilman 59 Dec 29, 2022
Rust bindings for the KING OF TIME API

Rust bindings for the KING OF TIME API Example Prints if you are at work or not at work. $ cargo run --example tc -- status Record the time you start

Idein Inc. 2 Oct 11, 2021
A Discord bot for sending GeoGuessr challenge links that uses the GeoGuessr API written in rust.

GeoGuessr-bot-rs This is a simple implementation of a discord bot that send GeoGuessr-challenge links on demand. Features: Slash-commands Lightning-fa

Luukas Pörtfors 6 Nov 18, 2022
🚀 Fast and 100% API compatible postcss replacer, built in Rust

?? Fast and 100% API compatible postcss replacer, built in Rust

迷渡 472 Jan 7, 2023
A rust wrapper for the spam protection API

SpamProtection-rs Table of contents About Supported Rust version Features How to use Credits License About This repo has been shifted to the official

cyberknight777 28 Aug 5, 2022