MADS v2.0
MADS v2.0 introduces a set of new features and a breaking change in the plugin protocol.
NOTE: this document is a work in progress, while MADS v2 remains in beta.
What’s new in
v2.0
The new version introduces some important features, listed hereafter.
New build system
The whole CMake build system has been rewritten from scratch. It should be now much easier than it was to build MADS from source. Nonetheless, installing binaries remains the suggester way to go.
Authentication and Cryptography
This is the single biggest new feature (and the reason for a major version change from 1.x to 2.x), which enables the use of MADS in production environments. MADS now supports optional encrypted communication via the underlying ZeroMQ protocol.
Cryptography is provided via CURVE library, which implements elliptic curve cryptography via public/private key pairs. Each agent has its own private key and the public key of the broker, while the broker has its private key and the keys of all agents.
The mechanism also provides an optional whitelist authentication for a given list of IPs (via mads.ini).
The mads --keypair command creates a valid keypair for the current device, then the broker and each agent can be started with the --crypto option for enabling encrypted communication. Only agents with valid keys can then join an encrypted MADS network.
Note that macOS version requires the libsodium library, which can be installed with brew install libsodium. The Linux version requires libsodium23 (sudo apt install libsodium23).
Windows specific
On Windows, you can now run commands as on unixes, i.e. mads broker in place of mads-broker. Of course, the dash version continues to work.
Libraries
Before v2.0, MADS Agent C++ class was available in a header only file. This made it harder to integrate MADS into other languages.
With MADS v2.0, the standard MADS installer provides both a static and a shared library, libMadsCore.[so|dll|dylib], plus a host of C++ header files. The libraries also provide a pure C wrapper interface (and its corresponding header agent_c.h). This makes it easier for:
- implementing custom agents in any language that has a pure C interface (i.e. probably ANY language)
- releasing within the MADS installer a Python 3 interface, available as a module
- compiling the library for Android (planned for the next month), which will allow to write MADS agents in — for example — in C# within GUIs to be used on a tablet of phone
The MadsCore library embeds all the libraries needed by MADS: for MongoDB, ZeroMQ, Snappy compression, Sodium for encription, and others. Only OpenSSL or equivalent cryptography libraries are needed.
The C wrapper (and as such the Python module) is not a complete alternative to the C++ class, as it only provides a minimal subset of functions. For example, the C++ Mads::Agent class includes methods that simplify the creation of timed main loops, which is not provided by the C or Python interfaces (where you shall provide loop control by yourself).
New/changed commands
New sub-commands and agents are provided by MADS v2.0:
- To check and download new versions: the command
mads updateshows a list of the available download links for the latest official MADS release (on GitHub). Similarly,mads betaprovides a list of the available download links for the latest beta version (if available) - To monitor running agents: a new plugin is installed:
mads sink monitor.pluginis a sink agent that shows a table of the running agents together with the time delay between the last two published messages, colored in green, yellow or red according to pre-defined intervals (that can be set inmads.ini) - Simpler plugin loading: the sub-commands
source,filter, andsinkalso accept the plugin name without extension, i.e. asmads sink monitorrather thanmads sink monitor.plugin - Director GUI: the command
mads directorlaunches a GUI for coordinating a number of agents on the same machine. See the guide
Plugins
Another important change is the support for Dynamic Loop Timing (DLT) in plugins. In practice, the loop time period for source and filter plugins can be dynamically adapted from within the plugin, making it faster, slower, or going back to the default value.
To use DLT, you simply have to set the instance variable std::chrono:milliseconds next_loop_duration to the desired duration of the next iteration of the main execution loop. Set it again to 0 re revert back to the nominal (and constant) loop timing.
The DLT allow the development of plugins that can adapt the frequency of operation: for example, we could have a plugin that replays a stream of data collected at irregular time steps.
Receive queue size control
MADS v2.0.0 allows to set the ZeroMQ receive queue size (aka High-Water-Mark level). By default, ad in previous versions, the queue size is 1000: any agent can queue up to 1000 messages while it performs the processing, and once the queue is full new incoming messages are discarded.
Now MADS allows to set the queue size via settings. For example:
[my_agent]
queue_size = 1effectively removes the queue, and if messages arrive faster than they can be processed, they are immediately dropped.
The queue is important for agents that accept incoming messages at variable rates, possibly in bursts. This allow a thorough processing of the incoming messages. But if the incoming messages arrive at a regular and sustained rate faster than the agent’s processing capability, the queue is ineffective and only results in delay until full, then excess messages are discarded (silently). In such a condition, you want:
- to reduce the rate of incoming messages, or:
- to reduce the queue size to 1 so that excess messages are discarded and the older one is processed
Unfortunately, due to ZeroMQ architecture, it is not possible to only keep the most recent message (but if you think about that, it makes no practical difference).
Plugin template generation
The mads plugin command, which generates stub for plugins, has been improved in order to generate stub C++ files with more detailed comments. In particular, the purpose of the different return_types have been explained in comments.
Breaking changes
A major version jump usually means that some breaking change has to be expected. In fact, we are also updating the plugin loading mechanism (or, plugin protocol) in order to make plugins more effective an easy to code.
Upon loading, a plugin signals its protocol version to the plugin loader. The protocol version was 5 for MADS v1.4, and it is now 7 for MADS v2.0. This means that plugins developed for MADS v1.4 must be updated and re-compiled.
The user-facing changes in the new protocol version are:
- support for the
std::chrono:milliseconds next_loop_durationvariable (see above) - change of
void set_params(void const *params)signature tovoid set_params(const json ¶ms). This makes it easier the use of theparamsparameter, since a more flexible void pointer is rarely needed. No need for a cast in the function body, and any call toset_params()(typically in the body of themain()test function) must be adapted to take ajsoninstance rather than a pointer to it. - methods for loading/publishing data are updated to also accept binary blobs. This allows to attach to any message an arbitrarily large binary object (images, data serialized more efficiently than with JSON)
- update the
CMakeLists.txtto fetch the proper version of the plugin base class (with tag v2.0-P6).
To update the plugin source code, proceed as follows:
- delete the directories
build/plugin-*(much faster than deleting the wholebuildfolder); this forces CMake to re-download the updated version. If it does not work, delete the wholebuildfolder and rebuild it from scratch - update the plugin source file either manually, or by using the
update_plugin_source.pyscript that is available either in$(mads -p)/python:
$(mads -p)/python/update_plugin_source.py src/*.cpp CMakeLists.txt- re-compile the plugin:
cmake -Bbuild && cmake --build build