C++ - How to write a qimessaging service¶
This document will teach you how to write your very own qimessaging service, so that your new shiny object can be used by other qimessaging services and clients, locally or remotely, and from many different programming languages.
Limitations¶
There are some restrictions on what you can do:
- Do not use class member data.
- Output parameters are not supported: you should not take pointers as arguments, or non-const references.
- Do not use methods in transmitted struct, as they will not be available in other languages: put the methods in an associated class.
To understand those restrictions, keep in mind that qimessaging is a middleware that knows how to transport data (like primitive types, structs, and containers of the above), and how to make calls to remote methods, signals and properties, but cannot mix the two.
Write your service¶
Your service can be a simple class which is registered in the type system (see type registration):
#include <qi/anyobject.hpp>
struct Mosquito
{
double yaw,theta,distance;
};
QI_TYPE_STRUCT(Mosquito, yaw, theta, distance)
class Cat
{
public:
void meow(int volume);
bool setTarget(const Mosquito& m);
qi::Property<float> hunger;
qi::Property<float> boredom;
qi::Property<float> cuteness;
qi::Signal<Mosquito> onTargetDetected;
};
QI_REGISTER_OBJECT(Cat, meow, setTarget, hunger, boredom, cuteness,
onTargetDetected);
Now your class and its types (Mosquito) are known by the type-system. If you don’t want to make a module, you can skip directly to the Manual way section.
You will then put this class in a module (like a library) that you will be
able to load dynamically. You will also need to advertise a factory to be able
to make a Cat
out of this module, like this:
void registerCat(qi::ModuleBuilder* mb)
{
mb->advertiseFactory<Cat>("Cat");
}
QI_REGISTER_MODULE("catsimulator", ®isterCat);
Your module will be called catsimulator
(must be the same name that you will
put in your CMake file). You can now write a CMakeLists.txt and you’re done:
cmake_minimum_required(VERSION 2.8)
project(catsimulator)
find_package(qibuild)
find_package(qimodule)
qi_create_module(catsimulator
SRC
src/cat.cpp
DEPENDS
QI
)
Remember that the name you put in qi_create_module
must be the same as the
one in QI_REGISTER_MODULE
. For more information about modules, see
qi::AnyModule
.
Running your service¶
Fully automated way¶
You can start your service by using qilaunch, like this:
qilaunch -n catsimulator --object catsimulator.Cat
qilaunch instantiates your service and registers it on the ServiceDirectory. It will forward its logs to the LogManager if present and will initialize breakpad to make a minidump when it crashes. You can stop it at any time with CTRL-C.
For more information on qilaunch, read Using qilaunch.
Semi-automated way¶
You can also instantiate your object manually and expose it on a session. In
this example, ApplicationSession
parses the command line arguments to find out
what the user wants, i.e.:
- which type of session (listening or connected to a ServiceDirectory)
- on which address
And then it initializes a session accordingly.
#include <qi/applicationsession.hpp>
int main(int argc, char** argv)
{
qi::ApplicationSession app(argc, argv);
app.start();
qi::SessionPtr session = app.session();
session->loadService("catsimulator.Cat");
app.run();
}
Manual way¶
If you don’t want to use a module at all but simply make a binary that publishes your service, you can just do, similarly to the example above:
#include <qi/applicationsession.hpp>
int main(int argc, char** argv)
{
qi::ApplicationSession app(argc, argv);
app.startSession();
qi::SessionPtr session = app.session();
auto cat = boost::make_shared<Cat>();
session->registerService("CatService", cat);
app.run();
}
Then, you don’t need to use qi_create_module
in your CMake file, you can
just use qi_create_bin
.
The session will keep a reference on cat until it is closed or CatService is unregistered.