Bluetooth-Devices / dbus-fast

A faster version of dbus-next
MIT License
31 stars 8 forks source link

Add D-Bus signal APIs #11

Open dlech opened 1 year ago

dlech commented 1 year ago

In Bleak, we have some code that is a nice wrapper around org.freedesktop.DBus.AddMatch and org.freedesktop.DBus.RemoveMatch that would be nice to include in this package to make subscribing to signals in the low-level API easier.

https://github.com/hbldh/bleak/blob/develop/bleak/backends/bluezdbus/signals.py

mdegat01 commented 1 year ago

The proxy interfaces of the library already allow you to attach a callback to a signal and then remove that listener later using on_<signal> and off_<signal> as described here: https://python-dbus-next.readthedocs.io/en/latest/high-level-client/aio-proxy-interface.html . Seems like that's what you're describing and showing? Or is there an issue with that feature I'm not aware of?

dlech commented 1 year ago

We are using the low-level APIs, not the high-level APIs. And even if we were using proxies, they suffer from a race condition where you can't subscribe to the signals until after the object is created and so you end up having to call "GetManagedObjects" twice.

Additional motivation: https://github.com/altdesktop/python-dbus-next/issues/53

mdegat01 commented 1 year ago

Interesting, didn't know that. In supervisor we currently use the low-level APIs for signal listening as well but for a different reason. Currently in supervisor the only time we listen for signals is for confirmation of an asynchronous action. Like when changing the active connection in network manager we then listen for the StateChanged signal to confirm it worked. Similar when installing a rauc bundle file it fires the Installer.Completed signal when done.

So we can't use the on_<signal> functions there because we aren't continuously listening for a signal and acting on each one. Instead we specifically listen for a signal one time after we take an action and wait for it, using it to craft the response to the client that initiated it. This for reference is a capability I was also considering moving to the library in the future, basically a with_<signal> method that supports this:

async with proxy.with_signal() as signal:
  proxy.call_start_something_async()
  resp = await signal.wait_for_signal()

I was also planning to enhance supervisor with the ability to continuously listen for PropertiesChanged events on the objects it cares about. I had been planning to use the high-level client for this but I guess I'll have to review this now.