Announcing D-Bus plugin for Licq

4 views
Skip to first unread message

Anders Olofsson

unread,
Oct 12, 2013, 5:34:54 AM10/12/13
to licq...@googlegroups.com
I've just pushed the first version of a D-Bus interface plugin for Licq.

I mainly created this as a way to display notifications from Licq, like
the osd plugins but in a separate process instead of having it as a
plugin to Licq. I also added support for method calls to request
information or control Licq in the hopes that others will be able to
find further use for this plugin.
The current API is very limited but should be relatively easy to extend
depending on which use cases we want to support.

More features or suggestions on what should be included are welcome.

I'm not experienced with making D-Bus interfaces, so if anyone has
better ideas for how the API should look please let me know.

/Anders

Erik Johansson

unread,
Oct 12, 2013, 6:30:20 AM10/12/13
to Anders Olofsson, licq...@googlegroups.com
Nice work!

I would be nice if you could add the features needed to make it possible to browse available licq methods using e.g. qdbusviewer.

// Erik




/Anders

--

--- You received this message because you are subscribed to the Google Groups "Licq Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to licq-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Erik Johansson
Home Page: http://ejohansson.se/
PGP Key: http://ejohansson.se/erik.asc

Anders Olofsson

unread,
Oct 12, 2013, 8:30:54 AM10/12/13
to licq...@googlegroups.com
It should just be a matter of implementing
org.freedesktop.DBus.Introspectable. I think it should be pretty easy to
add. I'll give it a try.

/Anders


On 2013-10-12 12:30, Erik Johansson wrote:
> Nice work!
>
> I would be nice if you could add the features needed to make it possible
> to browse available licq methods using e.g. qdbusviewer.
>
> // Erik
>
>
> On Sat, Oct 12, 2013 at 11:34 AM, Anders Olofsson <fl...@licq.org
> <mailto:fl...@licq.org>> wrote:
>
> I've just pushed the first version of a D-Bus interface plugin for Licq.
>
> I mainly created this as a way to display notifications from Licq,
> like the osd plugins but in a separate process instead of having it
> as a plugin to Licq. I also added support for method calls to
> request information or control Licq in the hopes that others will be
> able to find further use for this plugin.
> The current API is very limited but should be relatively easy to
> extend depending on which use cases we want to support.
>
> More features or suggestions on what should be included are welcome.
>
> I'm not experienced with making D-Bus interfaces, so if anyone has
> better ideas for how the API should look please let me know.
>
> /Anders
>
> --
>
> --- You received this message because you are subscribed to the
> Google Groups "Licq Development" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to licq-dev+unsubscribe@__googlegroups.com
> <mailto:licq-dev%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/__groups/opt_out
> <https://groups.google.com/groups/opt_out>.

Kevin Krammer

unread,
Oct 12, 2013, 9:15:43 AM10/12/13
to licq...@googlegroups.com
On Saturday, 2013-10-12, Anders Olofsson wrote:
> It should just be a matter of implementing
> org.freedesktop.DBus.Introspectable. I think it should be pretty easy to
> add. I'll give it a try.

It is usually also a good idea to provide a D-Bus introspection XML file as
part of the sources, potentially even installing it.

It is a way of documenting which interfaces are available as "public API" as
opposed to D-Bus being used for an internal purpose ("private API") or still
experimental features ("unstable API").

Cheers,
Kevin
signature.asc

Anders Olofsson

unread,
Oct 12, 2013, 9:25:31 AM10/12/13
to licq...@googlegroups.com
On 2013-10-12 15:15, Kevin Krammer wrote:
> On Saturday, 2013-10-12, Anders Olofsson wrote:
>> It should just be a matter of implementing
>> org.freedesktop.DBus.Introspectable. I think it should be pretty easy to
>> add. I'll give it a try.
>
> It is usually also a good idea to provide a D-Bus introspection XML file as
> part of the sources, potentially even installing it.
>
> It is a way of documenting which interfaces are available as "public API" as
> opposed to D-Bus being used for an internal purpose ("private API") or still
> experimental features ("unstable API").

It sounds like a good idea, but I have put all the contacts in the
object tree so it's not a fixed structure and the examples I have seen
for the introspective data is for a static structure only. Is it
possible to describe a runtime dynamic tree in a static text file? I
guess the interfaces could be documented but I haven't seen any example
on how to write it.

/Anders

Kevin Krammer

unread,
Oct 12, 2013, 10:15:13 AM10/12/13
to licq...@googlegroups.com
I am not sure I fully understand you so please correct me if I am wrong :)

As far as I can tell after a quick look into the code is that you have the
following interfaces:
org.licq.Core
org.licq.ContactList
org.licq.Contact
org.licq.Account

Each of these can be described in a separate XML file, each interface can be
applicable to one or more object paths.
I guess the first two are for a single object each, while the latter two apply
to multiple objects.

Both usages are fine, you don't have to document all possible object paths. It
helps "client" developers to mention object path patterns though, e.g.
"Contact objects implement the org.licq.Contact interface and can be found on
object paths /org/licq/ContactList/<protocol>/<contactId>"

or even

"...and can be listed by calling org.licq.ContactList.GetAccounts()"

Cheers,
Kevin
signature.asc

Kevin Krammer

unread,
Oct 12, 2013, 11:51:50 AM10/12/13
to licq...@googlegroups.com
On Saturday, 2013-10-12, Anders Olofsson wrote:
I had a better look at the implementation now and I think it would improve
maintainablity and extendability if handling of each interface were delegated
to a respective implementation.

E.g. something like an interface similar to DbusCallback but as a base for
each interface implementation:

class DbusAbstractInterface
{
public:
explicit DbusAbstractInterface(DbusInterface *conn);


virtual in dbusMethod(const char *path, const char *member ...);
..
protected:
DbusInterface *const m_conn;
};

And the implementations like
class DbusCoreInterface : public DbusAbstractInterface
{
....
};

And then registering an instance of each with the DbusCallback implementor
such that it only needs to do a lookup based on "iface" and then delegate.

I think it would also be good to have GetAccounts() return an array of object
paths, i.e. D-Bus type "ao".
That allows "clients" to treat the values as opaque identifiers, allowing you
to change the scheme, e.g. have them as a flat list instead of grouped by
protocol, etc.

At some point it might be worthwhile to think about "bulk notifications", e.g.
a signal "ContactsStatusChanged" with D-Bus signature "a{s(us)}".
I.e. a map, where the key (first s) would be the contact identifier (or object
path if contacts are addressable individually) and the value would be the
status value and status text.

That might be benefitial if for example an accounting changing offline/online
status results in a whole set of contacts changing their status (only one
signal to send, only one signal to process on the client side).

Not sure if your plugin interface enables you to detect that though.

Cheers,
Kevin

P.S.: a bonus of having introspection XML files is that you can test how code
generators like qdbusxml2cpp or gdbus-codegen deal with them. If they fail to
produce valid code it would be an indication that there is something that
could be improved.
signature.asc

Anders Olofsson

unread,
Oct 13, 2013, 4:17:42 PM10/13/13
to licq...@googlegroups.com

I've pushed an update to make the plugin reply to introspect queries. It
seems to work in qdbusviewer so I hope I got it right.

>>> It is usually also a good idea to provide a D-Bus introspection XML
>>> file as part of the sources, potentially even installing it.
>>>
>>> It is a way of documenting which interfaces are available as
>>> "public API" as opposed to D-Bus being used for an internal purpose
>>> ("private API") or still experimental features ("unstable API").
>>
>> It sounds like a good idea, but I have put all the contacts in the
>> object tree so it's not a fixed structure and the examples I have
>> seen for the introspective data is for a static structure only. Is it
>> possible to describe a runtime dynamic tree in a static text file? I
>> guess the interfaces could be documented but I haven't seen any
>> example on how to write it.
>
> I am not sure I fully understand you so please correct me if I am
> wrong :)
>
> As far as I can tell after a quick look into the code is that you
> have the following interfaces:
> org.licq.Core
> org.licq.ContactList
> org.licq.Contact
> org.licq.Account
>
> Each of these can be described in a separate XML file, each interface
> can be applicable to one or more object paths.
> I guess the first two are for a single object each, while the latter
> two apply to multiple objects.

Yes, that is correct. But the only syntax I've seen is the introspect
data which includes object paths. Could you point to an example for how
the files should look if I only define interfaces without object paths?

Although I'm slightly skeptic to having another file describing the API.
Right now there are three "copies": The implemented code, the introspect
response in the code, and the examples in the README file.
Adding XML files as well would be a fourth copy which is at least one
too many to expect all of them to stay in sync.


> I had a better look at the implementation now and I think it would improve
> maintainablity and extendability if handling of each interface were delegated
> to a respective implementation.
>
> E.g. something like an interface similar to DbusCallback but as a base for
> each interface implementation:
>
> And then registering an instance of each with the DbusCallback implementor
> such that it only needs to do a lookup based on "iface" and then delegate.

This would require the plugin to instantiate objects for every contact
in Licq which would make the plugin much larger (both code and memory
usage).
If/when the API becomes larger it might be more efficient, but for now I
think I prefer to keep the code simple.


> I think it would also be good to have GetAccounts() return an array of object
> paths, i.e. D-Bus type "ao".
> That allows "clients" to treat the values as opaque identifiers, allowing you
> to change the scheme, e.g. have them as a flat list instead of grouped by
> protocol, etc.

Yes, it's probably more convenient for clients to get object paths
rather than account names. I'll change GetAccounts and GetContacts to
return object paths instead.


> At some point it might be worthwhile to think about "bulk notifications", e.g.
> a signal "ContactsStatusChanged" with D-Bus signature "a{s(us)}".
> I.e. a map, where the key (first s) would be the contact identifier (or object
> path if contacts are addressable individually) and the value would be the
> status value and status text.

The plugin get individual signals for each contact so this would require
buffering of status changes in the plugin.

Also, I tried to keep the DbusInterface class simple so right now it
can't create arrays of structs.

/Anders

Kevin Krammer

unread,
Oct 13, 2013, 5:06:11 PM10/13/13
to licq...@googlegroups.com
Am Sonntag, 2013-10-13, 22:17:42 schrieb Anders Olofsson:

> > Each of these can be described in a separate XML file, each interface
> > can be applicable to one or more object paths.
> > I guess the first two are for a single object each, while the latter
> > two apply to multiple objects.
>
> Yes, that is correct. But the only syntax I've seen is the introspect
> data which includes object paths. Could you point to an example for how
> the files should look if I only define interfaces without object paths?

The name attribute on the top level node element can be omitted.
Or you set it to "/", it will usually be ignored anyway.
See for example org.freedesktop.UPower.Device which all device nodes of UPower
implement independent of their actual object path:
http://cgit.freedesktop.org/upower/plain/src/org.freedesktop.UPower.Device.xml

> Although I'm slightly skeptic to having another file describing the API.
> Right now there are three "copies": The implemented code, the introspect
> response in the code, and the examples in the README file.
> Adding XML files as well would be a fourth copy which is at least one
> too many to expect all of them to stay in sync.

Hmm. I haven't thought about that. Usually the XML file is the source and the
implementation is generated by the respective binding's tools.
Have you considered using the C++ bindings?
http://dbus-cxx.sourceforge.net/quick_start_example_xml.html

Another option for reduction of redunancies might be to include the XML file
into the binary at build so it can be served as the runtime introspection
data.

Not sure how to best do that, usually also taken care of by the binding :-/

> > I had a better look at the implementation now and I think it would improve
> > maintainablity and extendability if handling of each interface were
> > delegated to a respective implementation.
> >
> > E.g. something like an interface similar to DbusCallback but as a base for
> > each interface implementation:
> >
> > And then registering an instance of each with the DbusCallback implementor
> > such that it only needs to do a lookup based on "iface" and then delegate.
>
> This would require the plugin to instantiate objects for every contact
> in Licq which would make the plugin much larger (both code and memory
> usage).

No, sorry, I probably wasn't clear.
I meant having one instance of each interface handler, e.g. one for
org.licq.Core, one for org.licq.ContactList, one for org.licq.Contact and so
on.
Each interface's callback entry points would still get the object path and
retrieve the respective C++ object just like you do now.

Flow would be like this
call to path=/some/contact/path iface=org.licq.Contact member=GetName comes in
-> main interface does a lookup, e.g. in a std::map<string,
DbusAbstractInterface*>
-> if !found => error
-> else delegate to found object, pass path and member and other args
-> uses internal pointer to main interface to respond.
Cheers,
Kevin
signature.asc
Reply all
Reply to author
Forward
0 new messages