[RFC] dbus-python API (re)definition

Simon McVittie simon.mcvittie at collabora.co.uk
Fri Sep 1 04:30:25 PDT 2006


On Thu, 31 Aug 2006 at 15:01:56 -0400, John (J5) Palmieri wrote:
> Highlevel plan on how I see objects and BusNames working:
> 
> Bus Names are registered on a connection, not as part of the object.

Sounds good to me! A method on the Bus object that encapsulates
the connection to the bus, perhaps?

> Objects are created with an object path and then registered on the
> connection.

Makes sense.

> The object path is grafted onto the connection and introspection data is
> (re)generated.
> Whole object paths can be removed or just one node at any time

Also makes sense.

> A new type of object should be available which processes all methods
> with object paths underneath its node.  Methods it does not implement
> get passed down the chain.  It has a list of all of its children and can
> pass methods down to them even if it implements a method.

This is starting to look like the HTTP namespace -> objects mapping
performed by web frameworks like Rails or Django :-)

> Don't bother deprecating dbus_bindings.  If an app uses it, they need to
> not.

OK, I'm happy to break it!

> As for main loop integration there is already a generic API that glib
> uses.  This should be done for any other mainloop.  The only other thing
> we should provide is a generic loop API for applications that wish to
> poll or don't need a complicated mainloop.

Dafydd Harries suggests using an API compatible with that of Twisted
(at a "duck typing" level, at least) so we can immediately use any of the
Twisted main loops. If I do that, I'll provide at least one main loop
implementation so dbus-python can work standalone - Twisted Core is
quite a large thing to depend on.

> proxies and service should be renamed.  Proxy is a bad word to use and
> so is service.  I like consumer/provider as an idiom since this is not a
> strict one to one client/server architecture.  I'm not sure if those
> make good module names.  export is ok, though I'm not sure if I like
> that either.  Perhaps we should sit down and come up with a standard set
> of vocabulary and produce a glossary.

That would be very useful. I'm trying to avoid writing about proxies,
services, clients and servers in the docstrings, but it's hard work!

I'm not entirely sure what your objection is to "proxy" - the real
object to which its implementation is delegated is over in some
other process, but what I do have is a proxy for the real object, which
behaves the same. Or could you explain what you mean by proxy being a bad
word?

I can see your objection to "service" more clearly, since any process
can export an object and there isn't a strict division between
services/servers and clients. I quite like the export/import metaphor (by
analogy to Perl's @EXPORT and Python's "from ... import ...", although
it doesn't actually match real-world exporting and importing very well).

As a term for the exported object, perhaps "provided object" would work,
but I don't think "provider" works except as a name for the application or
endpoint doing the providing, and "consumed object" as a term for what we
now call the proxy doesn't really work for me :-)

On the service side, "published object" is perhaps another possibility.
On the client side, "remote object", perhaps?

As a use-case for this terminology, I'd like some names that make sense
in these contexts:

  # in the implementation of the Epiphany browser (pretend it's written in
  # Python for a moment, although it's actually C)
  class Browser(dbus.ExportedObject):           # <-- here
      @dbus.exported_method(...)
      def loadURIList(URIs, Options, Timestamp):
          ...

  # in some program that wants to display a URL, perhaps an email client
  browser = dbus.RemoteObject(...)              # <-- and here
  browser.loadURIs(['http://dbus.freedesktop.org/'], '', 0)

As an attempt at a glossary, is this right? Potential terminology in square
brackets.

* The participants in D-Bus are connection [endpoint]s.

* A process may have zero or more endpoints. Any number of endpoints
  in the same process may be connected to the same remote endpoint
  (e.g. a single process can have multiple connections to the session
  bus if the author feels like it).

* A [connection] connects exactly two endpoints.

* Connections are usually, but not always, between a peer and a [bus daemon].
  The bus daemon forwards relevant messages between all peers connected to
  it, in a star topology.

* A [peer] is any endpoint that isn't a bus daemon. It is connected to
  at most one other endpoint, which may be either a peer or a bus daemon.

* For specialized uses, two peers can connect directly; one of them must
  listen for connections (e.g. using DBusServer) and the other must connect to
  it. In this peer-to-peer situation every message emitted by one peer is
  received by the other. The client/server thing is entirely
  a matter of how the connection is initiated - once established, the
  connection is completely symmetric (like BEEP rather than HTTP).

* Every endpoint has zero or more exported [object]s, each identified by
  a slash-separated [object path] which is unique within the endpoint.

* Endpoints which export objects used to be called services. This term
  is deprecated.

* Every peer connected to a bus daemon has one or more [bus name]s,
  consisting of exactly one [unique name] and zero or more [well-known
  name]s. Allocation of these is done by the bus daemon.

* Well-known names used to be called service names. This term is
  deprecated.

* Each bus daemon has the bus name "org.freedesktop.dbus" and will never
  allow a peer to be given this name. The bus daemon does not have a
  unique name.

* Objects implement one or more [interface]s; they always implement the
  unnamed interface. The set of [interface]s implemented by an object
  may change at any time. Interfaces consist of methods and signals
  with signatures; the object may, but need not, allow these to be
  discovered by D-Bus introspection. The set of methods and signals
  associated with a named interface on an object may change at any time,
  but this is frowned upon. The set of methods and signals associated with
  the unnamed interface should not be relied upon; bindings are likely
  to implement the unnamed interface as the union of all named
  interfaces implemented by the object, with some arbitrary conflict
  resolution if interfaces have a method of the same name, but are not
  required to do so.

> Signal registering and registering is a tricky subject.  Right now we
> have two ways of doing it.  Placing a match rule on the connection or
> connecting to a signal from a proxy.  The proxy method is really bad and
> needs to go away since it blocks methods (only on the objects and not
> the interfaces) from having that name and the object must be around
> before you can actually connect to it.

I must admit I hadn't spotted this, since in Telepathy we always use the
connect_to_signal method on the Interface wrapper.

Surely you should be able to create a proxy for a remote object that
doesn't actually exist yet, and have it work OK until you try calling a
method?

> Proposal is to have one set of
> APIs for registering signals listeners on a connection.  In this
> scenario you can pass in a proxy and it will pick up all of the needed
> info.  The connection will listen to name_owner_changed signals and
> register and unregister match rules based on flags such as "if service
> changes connect signal to new service", "drop listener on change",
> "follow first connected service" or "service must be present when I
> register".  The current match rule format can also be used with the same
> flags.  Lifecyle of listeners are tied to the connection and dictated by
> the flags but rules should be able to be removed in other ways such as
> by id.

I note with amusement that despite deprecating the terms, you still talk
about services and proxies because they're the clearest way to express
what you mean :-)

        Simon


More information about the dbus mailing list