altdesktop / python-dbus-next

🚌 The next great DBus library for Python with asyncio support
https://python-dbus-next.readthedocs.io/en/latest/
MIT License
187 stars 59 forks source link

'AddMatch' request only working after creating proxy object/interface #83

Closed elParaguayo closed 3 years ago

elParaguayo commented 3 years ago

I have a slightly odd situation where I'm subscribing to signals using AddMatch rather than the on_signal_name from the interface.

Basically, I connect to the bus and send an AddMatch request with the appropriate rule and then attach a handler for the messages. However, I don't receive any messages unless I've created a proxy_object and interface. I don't think these are necessary so I'm not sure what's going on.

My code is:

from dbus_next.aio import MessageBus
from dbus_next import Message
from dbus_next.constants import MessageType, BusType
import asyncio

loop = asyncio.get_event_loop()

def msghandler(msg):
    print(msg.body)

async def main():
    bus = await MessageBus(bus_type=BusType.SESSION).connect()

    # I only get messages if these two lines are uncommented.
    intro = await bus.introspect("org.freedesktop.DBus", "/org/freedesktop/DBus")
    obj = bus.get_proxy_object("org.freedesktop.DBus", "/org/freedesktop/DBus", intro).get_interface("org.freedesktop.DBus")

    # Sending the message makes no reference to the object/interface above
    msg = await bus.call(
                 Message(message_type=MessageType.METHOD_CALL,
                 destination="org.freedesktop.DBus",
                 interface="org.freedesktop.DBus",
                 path="/org/freedesktop/DBus",
                 member="AddMatch",
                 signature="s",
                 body=["type='signal',member='NameAcquired']))
    bus.add_message_handler(msghandler)

    while True:
        await asyncio.sleep(1)

loop.run_until_complete(main())

Am I being stupid?

elParaguayo commented 3 years ago

Actually - I don't think that "AddMatch" message is doing anything at all. If I delete that line, I still get the same messages which, on closer inspection, are "NameOwnerChanged" signals. So, I guess by creating the interface object, I subscribe to every signal on that interface and so the generic message handler displays everything.

So the real question is still why my AddMatch message doesn't work. Will dig some more - probably something obvious...

acrisci commented 3 years ago

One tip is that when using the low level interface, always check if the call was successful.

assert msg.message_type is MessageType.METHOD_RETURN
elParaguayo commented 3 years ago

Thanks. The call is successful.

I changed the rule to just being

type=`signal`

and I did get responses with NameOwnerChanged but no NameAcquired signal.

This feels like those signals are being blocked somehow as they are visible if I use dbus-monitor --profile.

EDIT: or it's just not possible to create a match rule for that signal and I have to use NameOwnerChanged instead.

EDIT 2: According to the docs, the NameAcquired signal is sent to a specific application when it gains ownership of a name. I wonder if that stops me from catching it as I'm not the intended recipient.

elParaguayo commented 3 years ago

OK - we can close this.

From my testing, it looks like NameAcquired is only available via the BecomeMonitor method. Once that's set up, it behaves as expected.

    msg = await bus.call(
                 Message(message_type=MessageType.METHOD_CALL,
                 destination="org.freedesktop.DBus",
                 interface="org.freedesktop.DBus.Monitoring",
                 path="/org/freedesktop/DBus",
                 member="BecomeMonitor",
                 signature="asu",
                 body=[["type='signal',member='NameAcquired'"],0]))