diwic / dbus-rs

D-Bus binding for the Rust language
Other
585 stars 131 forks source link

Async signal match not working #455

Closed AndreaRicchi closed 9 months ago

AndreaRicchi commented 10 months ago

Hi, I'm currently facing a problem where the (almost) same code works in sync mode but doesn't in async mode. In particular, I'm trying to intercept the Connman ServiceChanged signal.

sync code:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let c = Connection::new_system().unwrap();
    // Add a match for this signal
    let mr = NetConnmanServicePropertyChanged::match_rule(None, None).static_clone();
    let _ = c.add_match(mr, |s: NetConnmanServicePropertyChanged, _, _| {
        println!("NetConnmanServicePropertyChanged: {:?} {:?}", s.name, s.value);
        true
    });

    // Wait for the signal to arrive.
    loop {
        c.process(Duration::from_millis(1000)).unwrap();
    }
}

async code:

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (resource, conn) = connection::new_system_sync()?;

    let _handle = tokio::spawn(async {
        let err = resource.await;
        panic!("Lost connection to D-Bus: {}", err);
    });

    let mr = NetConnmanServicePropertyChanged::match_rule(None, None);
    let _ = conn
        .add_match(mr)
        .await?
        .cb(|_, s: NetConnmanServicePropertyChanged| {
            println!("NetConnmanServicePropertyChanged: {} {:?}", s.name, s.value);
            true
        });

    let _ = _handle.await;

    unreachable!()
}

I'm practicing both Rust and DBus so any suggestions are more than welcome.

diwic commented 9 months ago

This row: let _ = conn /* etc */ I think drops the match too early. Maybe you could do let x = conn and then reference the variable between _handle.await and unreachable!() similar to what the example does?

AndreaRicchi commented 9 months ago

You are actually right. With this code it works:

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (resource, conn) = connection::new_system_sync()?;

    let _handle = tokio::spawn(async {
        let err = resource.await;
        panic!("Lost connection to D-Bus: {}", err);
    });

    {
        let proxy = Proxy::new(
            "net.connman",
            "/",
            Duration::from_millis(5000),
            conn.clone(),
        );
        let services_array = NetConnmanManager::get_services(&proxy).await;
        parse_services(services_array.unwrap());
    }

    let mr = NetConnmanServicePropertyChanged::match_rule(None, None);
    let incoming_signal = conn
        .add_match(mr)
        .await?
        .cb(|_, s: NetConnmanServicePropertyChanged| {
            println!(
                "NetConnmanServicePropertyChanged: {:?} {:?}",
                s.name, s.value
            );
            true
        });

    let _ = _handle.await;

    conn.remove_match(incoming_signal.token()).await?;

    unreachable!()
}

Thanks for the help.