Proxy Objects & Interfaces In DBussy

Lawrence D'Oliveiro ldo at geek-central.gen.nz
Thu May 25 04:22:53 UTC 2017


On Wed, 24 May 2017 13:32:40 +0100, Simon McVittie wrote:

> If Introspect() is called synchronously, like any other synchronous
> method call it will block the main loop, and can result in message
> re-ordering[1], which in the worst case can break the intended
> semantics of D-Bus APIs.

This is why asynchronous calls are so important. But they are a pain to
do with callbacks, which is why you need coroutines.

Referring to my DBussy Examples repo again, look at the list_bus_names
example script. This one makes use of non-blocking APIs to talk to the
D-Bus daemon itself. The non-blocking API is obtained with this call:

    dbus_daemon = ravel.def_proxy_interface \
      (
        ravel.INTERFACE.CLIENT,
        name = "DBusDaemon",
        introspected = dbus.standard_interfaces[DBUS.INTERFACE_DBUS],
        is_async = True
      )(connection = conn, dest = DBUS.SERVICE_DBUS)["/"]

Or, to break it down, first I construct the proxy interface class from
the predefined Introspection tree for this interface:

    DBusDaemon = ravel.def_proxy_interface \
      (
        ravel.INTERFACE.CLIENT,
        name = "DBusDaemon",
        introspected = dbus.standard_interfaces[DBUS.INTERFACE_DBUS],
        is_async = True
      )

I instantiate this to obtain a “root proxy” object that communicates
on a given connection with a destination bus name:

    root_proxy = DBusDaemon(connection = conn, dest = DBUS.SERVICE_DBUS)

and from there, I obtain the actual proxy object on a suitable object
path for making the API calls:

    dbus_daemon = root_proxy["/"]

The mainline can then obtain and print the necessary info:

    async def mainline() :
        reply = await (dbus_daemon.ListNames, dbus_daemon.ListActivatableNames)[activatable]()
        names = reply[0]
        for name in sorted(names) :
            if name.startswith(":") == unique :
                if show_owners :
                    reply = await dbus_daemon.GetNameOwner(name)
                    owner = reply[0]
                    sys.stdout.write("%s -> %s\n" % (name, owner))
                else :
                    sys.stdout.write(name + "\n")
                #end if
            #end if
        #end for
    #end mainline

Note how all the calls that generate D-Bus traffic are in “await”
clauses; these allow the event loop to continue to run while waiting
for the replies. Take away all the “await” and “async” keywords, and
the result is essentially identical to what you would write with
blocking calls. Thus, coroutines give you event-loop-friendliness with
very little increase in complexity.


More information about the dbus mailing list