This tutorial shows how to use the Apache Thrift Interface Definition Language (and relative compiler) to easily define RPC-based interfaces for YARP Modules.
Apache Thrift allows to define service interfaces in a simple definition file. Taking that file as input, a compiler generates source code which handles the RPC communication for commands and replies defined in the interface. This source code can therefore be used by a server that executes the commands and by clients that send requests to the server by means of simple function calls.
Let's assume that we want to create a new module that can receive commands on a RPC port to start/stop execution, and get/set some value. We can create a .thrift
text file that defines a Thrift service interface for our module like this:
where i32
is defined by the Thrift type system as a 32-bit signed integer, and bool
is a boolean value (true or false), one byte. Note that each argument of a function is associated to a unique, positive integer identifier. For a complete explanation of the Thrift IDL, please see Thrift IDL in YARP: advanced tutorial.
Now that we have our nice and clear interface definition, we want to generate the source code that provides this interface in YARPic terms, and implements the RPC communication process that occurs between a client that invokes a function call and the server that exectutes it.
Using CMake, generation of code for our demo.thrift file can be performed automatically during the configuration process. We create a CMakeLists.txt
configuration file in which we call the yarp_idl_to_dir
macro:
We can now run CMake to set up an out-of-source tree build from command line:
The YarpIDL macro defines a CMake "advanced" option, ALLOW_IDL_GENERATION, which is by default set to OFF if generated code is already present in the desired directory; we enable it with the -D ALLOW_IDL_GENERATION=ON option. We should now see two folders, "include" and "src", appear in the source tree, together with a demo_thrift.cmake file that helps CMake keep track of the generated files. Inside include
, we find a Demo.h
header file, which provides the interface:
src
instead contains a Demo.cpp
file that provides implementation for the RPC communication, but there's no need to bother with it: all we need to care about is the interface!
It is now time to provide an implementation for the functions we defined in the service interface. Let's create a DemoServer.cpp
file in which:
The thirft engine generates all the required code for the client. Clients can directly invoke remote procedures on the server using a proxy object (generated by thrift) attached to a YARP port.
Simple example:
A nicer altenative is to create a YARP RFModule that also implements the service interface:
The RFModule implementation:
And the main function:
A complete example of Thrift code generation and server/client creation with CMake is available in example/idl/thriftSimple
This is what we get when we launch server and client from command line (assuming a yarpserver is running, and we are in the "build" directory):
Client | Server |
$ ./demoClient --server /demoServerModule/cmd yarp: Port /demo/client active at tcp://10.255.36.53:10003 | $ ./demoServerModule ||| policy set to YARP_POLICY ||| YARP_POLICY: <snip> I know the answer! yarp: Port /demoServerModule/cmd active at tcp://10.255.36.53:10002 |
yarp: Sending output from /demo/client to /demoServerModule/cmd using tcp Hey are you up and running? No? Well... start! | yarp: Receiving input from /demo/client to /demoServerModule/cmd using tcp Indeed I am not running Starting! Indeed I am running |
Wonderful! I have a question for you... so, what's the answer?? What?? 42?? Are you kidding?? It's definitely 43!! | The answer is 42 I'm adding one to 42. That's easy :) OMG are you serious? The answer is 43?!? |
Got it? So, repeat after me: the answer is ... 43! Great! Ok you can relax now, I'll leave you alone | The answer is 43 Stopping! |
Bye yarp: Removing output from /demo/client to /demoServerModule/cmd | yarp: Removing input from /demo/client to /demoServerModule/cmd |
RPC calls can also be sent to the server from command line (note that commands with "_" in their name can be split):
$ yarp rpc /demoServerModule/cmd get_answer Response: 42 set_answer 28 Response: [ok] get answer Response: 28 is running Response: [fail] start Response: [ok] is running Response: [ok] stop Response: [ok] is_running Response: [fail]