MIRA
Authorities


Overview

Authorities can be seen as an id card that must be registered at the framework in order to be allowed to access channels (Channels), make RPC calls (Services and Remote Procedure Calls) and access the transformation tree (Transformation Framework). They are also used to uniquely identify modules that access the framework (see Names and namespaces). When an authority object is created, the namespace in which the module resides and a unique name within this namespace must be given. The authority automatically checks in and registers itself at the framework when a namespace and an id is given. All operations like publishing and subscribing to channels, accessing channels, sending an RPC call and so on are done by this Authority object.

// checking in an authority object
Authority authority("namespace", "name");

One can also create an authority and check it in later by calling checkin().

//create an invalid authority
Authority authority;
...
// and check it in later
authority.checkin("namespace", "name");

IWhena module has finished its operations it can checkout the authority. Additionally, the authority will check out automatically when the instance goes out of scope. This will stop all internal threads and handlers and any callbacks and notifications of new data. Additionally, the module will no longer be able to access a channel for reading or writing:

// checking us out manually
authority.checkout();

Threads and Dispatchers

For each authority object at least one thread is created via the thread dispatcher. It will provide a way to free the user from thread synchronization. By default, the thread will process all the channel subscriber callbacks for changed data (for channels the authority has subscribed on with a callback) as well as all RPC requests (see Threading) and handle all other registered handlers and timers. The thread is started by calling start() after checkin() or immediately in the constructor when specifying a namespace and an id:

Authority authority("namespace", "name");
// the thread is already started
// or
//create an invalid authority
Authority authority;
...
// and check it in later
authority.checkin("namespace", "name");
// start the main thread
authority.start();

Additionally the user can register different handlers that get called either immediately, when the dispatcher stops, at a specified time or in a specified interval.

For example one can add a handler that is called immediately when the authority is started inside the authorities dispatcher thread that acts as an initialization method. The thread blocks until the initialization function returns - no call to subscriber callbacks or RPC requests will be made until initialization is finished.

// initialize() will be called right at start up
Authority authority;
authority.checkin("namespace", "name");
authority.addImmediateHandlerFunction(boost::bind(&MyModule::initialize, this));
authority.start();

The user can add multiple immediate handlers and they will get called in the order they are registered. Finalize handlers will be called when the thread is going to be stopped.

// finalize() will be called right before shutdown
Authority authority;
authority.checkin("namespace", "name");
authority.start();
authority.addFinalizeHandlerFunction(boost::bind(&MyModule::finalize, this));
authority.stop(); // finalize is called before the main dispatcher thread ends

Moreover the user can create timers and register callback functions that are called when the timers are executed. Timers are executed in a defined interval or once when their invocation time is due. Calls to the timer callback functions are again handled by the same thread (see Timers).

Authority authority;
authority.checkin("namespace", "name");
// timer that calls the given function every second
authority.createTimer(Duration::second(1), &MyModule::myTimerFunc, this);
// timer that gets called once in 10 seconds
authority.createTimer(Time::now() + Duration::seconds(10), &MyModule::myTaskFunc, this);
authority.start();

The registered timer callbacks must have the following signature:

void myTimerCallback(const Timer& timer);

The timer parameter can be used to get statistics from the timer as well as stopping the timer.

The following code shows a complete example of launching a framework, creating an authority and registering multiple handlers and timers:

#include <fw/Framework.h>
using namespace mira;
void init()
{
MIRA_LOG(NOTICE) << "Init called";
// do some initialization stuff here like subscribing to and publishing channels
}
void startup()
{
MIRA_LOG(NOTICE) << "Startup called";
// do some startup stuff here that needs to be done each time the authority is started
}
void stop()
{
MIRA_LOG(NOTICE) << "Stop called";
// do some stopping stuff here that needs to be done each time the authority is stopped
}
void finalize()
{
MIRA_LOG(NOTICE) << "Finalize called";
// free memory here, deinitialize external stuff once the authority gets destroyed
}
void process(const Timer& timer)
{
MIRA_LOG(NOTICE) << "Process called at " << timer.current << " expected at "
<< timer.currentExpected;
// is called every second after init() and start() returned successfully
}
void task(const Timer& timer)
{
MIRA_LOG(NOTICE) << "Task called at " << timer.current;
// is called once 10 seconds after start
}
int main(int argc, char** argv)
{
// create a framework
Framework framework(argc,argv);
// create, checkin and start our authority
a.checkin("/", "MyAuthority");
a.createTimer(Duration::seconds(1), &process);
a.start();
// start the framework's main loop
return framework.run();
}

Sometimes it can be necessary to block in a timer callback or in an RPC request, but without disturbing and blocking channel subscriber callbacks. Therefore the user can enable a second thread that independently handles channel subscriber callbacks. The same applies for RPC requests. The user can enable another thread that independently handles RPC requests. Note that while an easy way is provieded to create these additional subscriber and RPC threads, the developer of the authority has to take care of synchronization between these independent threads himself (protecting data from concurrent access etc.). The additional threads can be enabled by specifying the flags in the constructor:

// enable two more threads. now we have three independent threads running.
Authority authority("namespace", "name", Authority::INDEPENDENT_SUBSCRIBER_THREAD |
Authority::INDEPENDENT_RPC_THREAD);

It is also possible to create a separate thread for each channel subscriber callback. See threading hints when subscribing to channels.

Hidden, internal and anonymous authorities

Anonymous Authorities

Sometimes the user wants to create multiple instances of one module without choosing a new unique name each time. For this purpose, anonymous authorities can be used. They can be created as follows by specifying a base name:

// checking in an anonymous authority object that resides in the "/" root namespace
Authority authority("/", "baseName", Authority::ANONYMOUS);

A unique name will be created for the authority by using the base name and a (random) UUID. To be able to get also the base name from an authority object, two methods are implemented:

For non-anonymous authorities both methods return the same name.

Hidden Authorities

Another form of authorities are hidden ones. They will automatically add a prefix to their name. This prefix is used to filter out hidden Services and Authorities e.g. in AuthorityView of miracenter.

// checking in a hidden authority object that resides in the "/" root namespace
Authority authority("/", "MyHiddenOne", Authority::HIDDEN);

Internal Authorities

If Authorities are meant to be used in the local framework only, one can use the INTERNAL flag. Internal Authorities automatically set the HIDDEN flag and remote frameworks are not notified about their existence.

Authority authority("/", InternalOne", Authority::INTERNAL);

Invisible Authorities

For some parts of the framework (e.g. the remote connection part) it is necessary that some authorities do not count as official subscribers or publishers for channels, even if they are subscribed to or have published that channel. For example a connection from a remote framework acts as a local publisher for all the channels of that remote framework. If another remote framework connects, it will ask about all the channels we have publishers for. In that case it would be very dangerous to tell the newly connected framework that we have a publisher for channels we do only receive from the first connected framework. It would lead to endless loops of sending data when each of the three frameworks is connected to each of the others.

In the very rare case you like/need to create an invisible subscriber/publisher authority, you can specify the INVISIBLE_PUBLISHER_SUBSCRIBER flag when creating the authority.

// checking in an authority object
Authority authority("namespace", "name", Authority::INVISIBLE_PUBLISHER_SUBSCRIBER);