dbus2 / zbus-old

Rust D-Bus crate.
https://gitlab.freedesktop.org/dbus/zbus
Other
49 stars 13 forks source link

MessageStream instance does not keep the connection open #248

Closed zeenix closed 1 year ago

zeenix commented 2 years ago

In GitLab by @jokeyrhyme on Jan 10, 2022, 24:49

Howdie, thanks so much for sharing this project!

My use case is that I'd like to build something similar to dbus-monitor, but making it easier to trigger executables/etc based on specific xdg-desktop-portal messages on DBus: https://gitlab.com/jokeyrhyme/xdp-spy-rs

Note that basic monitoring behaviour is already working, but I'm using the dbus crate which wraps the C implementation, and accessing DBus message bodies safely is not as convenient as I'd like

So, I'm now trying to switch to the zbus crate, especially because it uses serde-style deserializers for message bodies, which I'm very excited about

I've pretty much copy-pasted the example from here: https://docs.rs/zbus/2.0.0/zbus/struct.Connection.html#monitoring-all-messages, with my Cargo.toml containing:

[dependencies]
futures = "0.3"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
zbus = { version = "2", features = ["tokio"] }
zvariant = "3"

But, when I run this, it outputs a single NameLost signal and exits with code 0 (success):

Msg { type: Signal, sender: UniqueName(Str(Borrowed("org.freedesktop.DBus"))), path: ObjectPath("/org/freedesktop/DBus"), iface: InterfaceName(Str(Borrowed("org.freedesktop.DBus"))), member: MemberName(Str(Borrowed("NameLost"))), body: Signature: [
        s (115),
] }

If I switch to using a ConnectionBuilder instead, and set the name, then I get this above line twice and then it exits with code 0, e.g.

let connection = ConnectionBuilder::session()?
.name("com.gitlab.jokeyrhyme.xdg-spy")?
.build()
.await?;

My expectation is that dbus-monitor, and my master (with dbus crate), and my rewrite (with zbus crate) should all behave the same:

But, as the zbus monitoring example is not matching this behaviour, I'm assuming I've done something wrong or that there's perhaps something else I need to do to get it to match the behaviour?

Any suggestions on what I can try differently? Or why my session bus seems to work with the dbus crate and dbus-monitor but seems to behaviour differently with the zbus monitoring example?

Thanks so much!

zeenix commented 2 years ago

In GitLab by @jokeyrhyme on Jan 10, 2022, 24:54

Here's my complete src/main.rs which is the zbus monitoring example copied into a #[tokio::main] entry-point:

#![deny(clippy::all, clippy::cargo, unsafe_code)]

// see: https://docs.rs/zbus/2.0.0/zbus/struct.Connection.html

use futures::stream::TryStreamExt;
use zbus::{Connection, MessageStream};

#[tokio::main]
async fn main() -> zbus::Result<()> {
    let connection = Connection::session().await?;

    connection
        .call_method(
            Some("org.freedesktop.DBus"),
            "/org/freedesktop/DBus",
            Some("org.freedesktop.DBus.Monitoring"),
            "BecomeMonitor",
            &(&[] as &[&str], 0u32),
        )
        .await?;

    let mut stream = MessageStream::from(connection);
    while let Some(msg) = stream.try_next().await? {
        println!("{:?}", msg);
    }

    Ok(())
}
zeenix commented 2 years ago

In GitLab by @jokeyrhyme on Jan 10, 2022, 05:21

This is what I'm getting from the dbus session's logs:

$ journalctl -xfb | grep dbus
Jan 10 15:16:26 HOSTNAME dbus-daemon[3653]: [session uid=UID pid=3653] Connection :1.179 (uid=UID pid=107837 comm="target/debug/xdp-spy ") became a monitor.
Jan 10 15:16:26 HOSTNAME dbus-daemon[3653]: [session uid=UID pid=3653] Monitoring connection :1.179 closed.

And I get the same thing even when I switch the while into a looped-if (I just wanted to see if try_next() might be returning None when the stream/buffer is empty, but this doesn't seem to be a thing): e.g.

loop {
    if let Some(msg) = stream.try_next().await? {
        println!("{:?}", msg);
    }
}
zeenix commented 2 years ago

In GitLab by @jokeyrhyme on Jan 10, 2022, 05:27

My session configuration is the default for Archlinux:

<auth>EXTERNAL</auth>

<standard_session_servicedirs />

<policy context="default">
  <!-- Allow everything to be sent -->
  <allow send_destination="*" eavesdrop="true"/>
  <!-- Allow everything to be received -->
  <allow eavesdrop="true"/>
  <!-- Allow anyone to own anything -->
  <allow own="*"/>
</policy>
zeenix commented 2 years ago

@jokeyrhyme Thanks so much for reporting this issue and providing all possible details. Much appreciated. I can confirm that I can reproduce this issue and it's a bug in our API.

While I try my best to fix it ASAP for me, the workaround is easy: Keep the original connection around:

let mut stream = MessageStream::from(connection.clone());
zeenix commented 2 years ago

In GitLab by @jokeyrhyme on Jan 10, 2022, 22:17

Oh wow! Thanks so much! <3