/libringqt

A model/view based library to use the GNU Ring.cx protocol in QML and QtWidgets applications

Primary LanguageC++GNU Lesser General Public License v2.1LGPL-2.1

LibRingQt

libringqt is a library for GNU Ring, a secure communication platform.

It provides a full middleware personal information management system along with "turn key" QML and Qt Model/View bindings to make creating Qt+Ring.cx applications quick and safe.

Design

This library exposes about 40 QAbstractItemModels for various components of Ring. It also tracks the state internally and take great care of always exposing up to date and valid data.

It also provides a powerful extension system to integrate system specific assets such as contacts, ringtones, TLS certificates into the system so libringqt can track them automatically.

The API aims to be externally consistent and internally implemented as a set of state machines. The public API only exposes already validated data and prevent the state from being corrupted. Most public classes have an internal API only exposed to friend class.

Main concepts

Here are the main concepts of LibRingQt from the most abstract network entity down to an actual human. Each layer of abstract exists to cleanly handle any ambiguous obstacle, changes of cardinality or synchronization issues.

Call

An audio, video or historical call. This class is slowly deprecated in the API in favor of Event and will eventually be merged with the Media subsystem once it is no longer coupled with everything else.

Event / Calendar

A call, chat session, file transfer, voice mail or anything else that has a number of participant, a point in time where it starts and a point in time where it ends. This still being integrated and is a work in progress. It aims to help uncouple some of the phone related concepts and help migrate to a more generic multimedia / PIM platform as the scope is extended.

Groups of event are managed as Calendar objects. This is intended to be extended for an archival and cross device synchronization subsystem.

URI

Either a phone number, a SIP URI or an unique Ring account identifier.

ContactMethod

How to reach someone and the associated metadata for that specific way of reaching him/her/it. It has the following primary keys:

  • An URI (immutable)
  • An Account object (can be set only once)
  • A Person object (can be set only once)

The factory is IndividualDirectory and will take care of re-using and de-duplicating all instances.

A TemporaryContactMethod subclass exists with more related requirements but can only be used to build "true" ContactMethods (like in the search model).

This class instances are heavily indexed and the lookup is very fast.

Individual

Either a contact, a peer or the user itself. This is a very abstract view of someone. They always exists whether or not anything about the person is known. It is a set of ContactMethod and the concatenation of their metadata.

This object tracks the metadata associated with someone

Person

In concrete version of the individual. It has an undefined number of attributes.

This object tracks the information associated with someone

Main interfaces

TODO (callable, schedulable, present/tracked, collectable)

Supported platforms

  • Linux (amd64 and ARM)
  • macOS
  • Android
  • Windows (not tested as often, but known to work)

Qt 5.3+ is supported, Qt 5.6+ recommended.

Main subsystems

Media

The media namespace is where all classes related to live telecommunication classes reside.

Troubleshoot

A set of live problem solving algorithms intended to restore a coherent state when something goes wrong. Ring is always a distributed system and SIP is often an unreliable federation network. Add the use of UDP and you end up with a very fragile system that will eventually fail.

Libcard

Libcard is a semi independant component. It implements the VObject format as used by various IEFT Internet standards such as vCard or iCal. It uses modern C++ instead of Qt where it makes sense. While it's still quite coupled with libringqt clases, it aims at being it's own thing as much as possible.

Libcollection

The collection subsystem is a generic C++ CMS system to manage various assets on various platform. It is pluggable and allows to interact with third party systems using a standardized interface. There is contact collections for KDE Akonadi, macOS addressbook, vCard folders, Gnome Evolution. It's also used for TLS certificates, ringtones, calendars, blockchains, caching, voicemails and alsmost every other serializable classes.

QtWrapper / DBUS / Rest

They implement various IPC mechanism to talk to LibRing. QtWrapper just converts stdlib types into Qt types and link directly to LibRing. DBus and Rest use multiprocess message passing.

Both DBus and "qtwrapper" modes are currently officially supported. REST would eventually be nice and a msgpack mode would also be interesting for sandboxing.

LibRingQtQuick.Builder

Creating some objects require a non-trivial amount of imperative code. The bulder objects turn this imperative transaction into a declarative object.

They can be committed or canceled. All relevant steps and choices are turned into properties.

LibRingQtQuick.Locker

To mitigate the memory management mess mentionned below, some resource use shared pointers even if QtQuick is unstable when they are used. To mitigate this, the Locker objects track the workflow objects lifecycle internally so it becomes safe to use QtQuick with objects that don't follow the traditional object tree to manage their memory.

LibRingQtQuick.Filter

Proxy models with QtQuick bindings. The allow to get the "right data" without imperative JavaScript.

History

This library has been created to split the logic and GUI code of SFLPhone-KDE, a software phone. It was forked into LibRingClient then Ring-LRC when the SFLPhone application was EOLed and the GNU Ring project arose from its ashes.

It was moved from the KDE project to the GNU project. During the GNU era, the focus on Qt was dropped and a fork was necessary to keep alive the Qt APIs and models. The upstream GNU Ring project deprecated all relevant API used to create QML bindings. This fork is a community project and is no longer developed byu Savoir-faire Linux, the sole author of GNU Ring. It is maintained by one of the two original author of the code and sponsored by Blue Systems.

This project aims to continue the development of a QtCore based library with full QML compatible bindings for the GNU Ring project.

It's API is currently still unstable as the fork offers an unique opportunity to port the API to C++14 and get rid of old and unused components. Once the new API is finalized, this project will attempt to re-join the KDE project.

Memory management

This library memory management is a mix of legacy limitations and odd design requirements. Up until Qt4 support was dropped, C++11 wasn't usable along with Qt and this caused the proliferation if little classes to link everything. Up to this day, QML support for smart pointer is horrible and thus everything has to be exposed as raw pointers to be reliable (along with never using const*. This make it nearly impossible to delete the main objects.

To work around this and help the metadata "converge" to a smaller number of instances, there is online deduplication of most important objects. Factory classes are responsible of creating new instances, re-using old one and merging instances when all ambiguity is gone. Merging is done by using the object PIMPLE pointers (d_ptr). By deleting the d_ptr, it is possible to keep the memory usage mostly stable while never deliting the main pointers.

The problem with that is that signals are proxyed to all top-level objects and ==/!= cannot safely be used to compare pointers (as they might proxy the same "real" object). Unfortunately, it is also used in hundreds of places where it should not.

As a side effect, delete is used on the d_ptr instead of Qt own object tree to avoid accidentally deleting objects while one of their proxy is still alive.

Objects that are not intended to be exposed to the bindings use shared pointers. However if they ever become exposed to the bindings, it has to be reverted and this has so far caused a lot of problem (like converting QWeakPointer to QSharedPointer so the memory is in effect never freed and .data() becomes safe.

Credits

  • Author Emmanuel Lepage-Vallee
  • Author Stepan Salenikovich
  • Copyright Savoir-faire Linux 2004-2017
  • Copyright Emmanuel Lepage-Vallee 2015-present
  • Copyright BlueSystems 2017-present