zbus inside a glib mainloop

#rust #zbus #glib

As of zbus 2 beta 7 this no longer works; zbus now insists on managing the connection entirely on its own and provides a Futures-based async server API.

The rust DBus library zbus lets us get hold of the underlying file descriptor of a bus connection, which we can use to plug a zbus connection into the Glib mainloop:

use std::os::unix::io::AsRawFd;
use glib::source::SourceId;

pub fn source_add_zbus_connection_local<F: FnMut(zbus::Message) + 'static>(
    connection: zbus::Connection,
    mut on_message: F,
) -> SourceId {
    let fd = connection.as_raw_fd();
    glib::source::unix_fd_add_local(
        fd,
        glib::IOCondition::IN | glib::IOCondition::PRI,
        move |_, condition| {
            match connection.receive_message() {
                Ok(message) => on_message(message),
                Err(err) => eprintln!("Failed to process message on connection {}:{:#}", fd, err),
            }
            glib::Continue(true)
        },
    )
}

Then in main:

pub fn on_message(message: &zbus::Message) {
    dbg!(message);
}

fn main() {
    let context = glib::MainContext::default();
    if !context.acquire() {
        panic!("Failed to acquire context");
    } else {
        let mainloop = glib::MainLoop::new(Some(&context), false);

        let connection = zbus::Connection::new_session().unwrap();
        source_add_zbus_connection_local(connection, on_message);
        mainloop.run();
   }
}

Now on_message gets called every time a message is received on the bus connection, without blocking the regular glib mainloop.