Elektra
0.8.23
|
Not all of the features described in this document are implemented yet.
Development state:
This document explains how notifications are implemented in Elektra and how they can be used by application developers.
Elektra's notification feature consists of several components. While sending and receiving notifications is implemented by plugins, applications use APIs provided by wrappers in order to use different plugins.
A wrapper for notifications provides the API for receiving and handling notifications. A wrapper for I/O operations allows asynchronous notification processing by compatible plugins. The I/O wrapper consists of an interface used by transport plugins and multiple implementations of that interface called I/O bindings. A I/O binding implements the actual I/O management functions for a specific I/O management library. Applications typically use one I/O binding but can also use none or multiple I/O bindings.
Transport plugins exchange notifications via different protocols like D-Bus, Redis and ZeroMQ. For each type of transport there are two types of plugins: One for sending and one for receiving notifications. Developers do not interact with those plugins directly. The underlying transports are transparent to them. An internal-notification plugin implements notification handling functions and feeds back configuration changes from within the application.
When a configuration key is changed Elektra can generate change notifications that allow applications to process those changes. Developers can choose whether and how they want to receive and handle those notifications but not whether notifications are sent or which transport is used. How notifications are sent is specified in the notification configuration by the system operator.
System operators can mount the desired transport plugins and configure them (e.g. set channel, host, port and credentials) either globally or when mounting a configuration file.
They need to mount both sending and receiving plugins in order to use a transport.
Developers do not need to change their programs in order to start sending notifications. However without the integration of an I/O binding notifications are sent synchronously which will block normal program execution. For programs without time constraints (e.g. CLI programs) this may not be important, but for GUIs or network services this will have negative impact.
Since many different I/O management libraries exist (e.g. libuv, glib or libev) the transport plugins use the I/O interface for their I/O operations. Each I/O management library needs its own I/O binding. Developers can also create their own I/O binding for the I/O management library of their choice. This is described in the last section.
Each I/O binding has its own initialization function that creates a new I/O binding and connects it to the I/O management library. For this tutorial we will assume that libuv is used. For details on how to use a specific binding please look at the bindings' README.md in src/bindings/io/<binding>
.
We extend the example from the previous section where we already created our I/O binding and initialized the notification-wrapper. In order to handle change notifications a developer can either register a variable or a callback.
Values of registered variables are automatically updated when the value of the assigned key has changed. In the following example we will register an integer variable:
After calling elektraNotificationRegisterInt
the variable keyValue
will be automatically updated if the key in the program above is changed by another program (e.g. by using the kdb
CLI command). For automatic updates to work transport plugins have to be in place either at a mountpoint above the configuration or mounted globally.
Registering a variable is suitable for programs where the key's value is simply displayed or used repeatedly (e.g. by a timer or in a loop). If an initialization code needs to be redone after configuration changes (e.g. a value sets the number of worker threads) updating a registered variable will not suffice. For these situations a callback should be used.
The following snippet shows how a callback can be used if the value of the changed key needs further processing.
Developers can create their own bindings if the I/O management library of their choice is not supported by an existing I/O binding.
For details on see the example doc" binding" or the API documentation. Existing I/O bindings provide a good inspiration on how to implement a custom binding. Since a binding is generic and not application specific it is much appreciated if you contribute your I/O binding back to the Elektra project.