YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Thrift IDL in YARP: monitoring a connection

It is possible to monitor messages sent to a thrift service by using the portmonitor carrier.

Using thrift client

With YARP, it is possible to generate a Monitor class that can be used to inspect which messages are sent to the service, by passing the yarp.monitor = "true" annotation. For example, suppose we have the following structure in service.thrift

service Demo
{
i32 get_answer();
bool set_answer(1:i32 rightAnswer)
}

that is used to produce a static library

cmake_minimum_required(VERSION 3.19)
project(thriftEditor_example)
# Needed to link the static library from the plugin, on 64 bit
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
find_package(YARP COMPONENTS os idl_tools REQUIRED)
add_library(demo_protocol STATIC)
yarp_idl_to_dir(
INPUT_FILES Demo.thrift
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/demo
SOURCES_VAR IDL_GEN_SRCS
HEADERS_VAR IDL_GEN_HDRS
INCLUDE_DIRS_VAR IDL_INCLUDE_DIRS
PLACEMENT MERGED
)
target_sources(demo_protocol
PRIVATE
${IDL_GEN_SRCS}
${IDL_GEN_HDRS}
)
target_include_directories(demo_protocol
PUBLIC
$<BUILD_INTERFACE:${IDL_INCLUDE_DIRS}>
)
target_link_libraries(demo_protocol
PRIVATE
YARP::YARP_os)

a server

class DemoServer :
public Demo
{
int32_t mAnswer {42};
public:
int32_t get_answer() override { return mAnswer; }
bool set_answer(int32_t rightAnswer) override { mAnswer = rightAnswer; return true; }
};
int main(int argc, char* argv[])
{
YARP_UNUSED(argc);
YARP_UNUSED(argv);
DemoServer demoServer;
demoServer.yarp().attachAsServer(port);
if (!port.open("/demo/server")) {
return 1;
}
while (true) {
yDebug() << "Demo server running happily";
}
port.close();
return 0;
}
#define yDebug(...)
Definition Log.h:275
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void close() override
Stop port activity.
Utilities for manipulating the YARP network, including initialization and shutdown.
Definition Network.h:706
A port that is specialized as an RPC server.
Definition RpcServer.h:23
void delay(double seconds)
Wait for a certain number of seconds.
Definition Time.cpp:111
The main, catch-all namespace for YARP.
Definition dirs.h:16
#define YARP_UNUSED(var)
Definition api.h:162
add_executable(demo_server)
target_sources(demo_server PRIVATE DemoServer.cpp)
target_link_libraries(demo_server
PRIVATE
YARP::YARP_os
YARP::YARP_init
demo_protocol
)

and a client

int main(int argc, char* argv[])
{
YARP_UNUSED(argc);
YARP_UNUSED(argv);
yarp::os::RpcClient client_port;
client_port.open("/demo/client");
if (!yarp.connect("/demo/client", "/demo/server", "tcp")) {
yError() << "Could not connect to server /demo/server";
return -1;
}
Demo demo;
demo.yarp().attachAsClient(client_port);
int32_t answer = demo.get_answer();
demo.set_answer(answer + 4);
answer = demo.get_answer();
return 0;
}
#define yError(...)
Definition Log.h:361
A port that is specialized as an RPC client.
Definition RpcClient.h:22
add_executable(demo_client)
target_sources(demo_client PRIVATE DemoClient.cpp)
target_link_libraries(demo_client
PRIVATE
YARP::YARP_os
YARP::YARP_init
demo_protocol
)

It is possible to enable the generation of the FakeService::Monitor class in this way:

service Demo
{
i32 get_answer();
bool set_answer(1:i32 rightAnswer)
} (
yarp.monitor = "true"
)
yarp_prepare_plugin(demo_monitor
TYPE Demo::Monitor
INCLUDE ${IDL_GEN_HDRS} # FIXME there should be a way to get this automatically
CATEGORY portmonitor
INTERNAL ON
)
yarp_add_plugin(demo_monitor)
target_link_libraries(demo_monitor
PRIVATE
YARP::YARP_os
demo_protocol
)
yarp_install(
TARGETS demo_monitor
EXPORT demo_monitor
COMPONENT demo_monitor
LIBRARY DESTINATION ${YARP_DYNAMIC_PLUGINS_INSTALL_DIR}
ARCHIVE DESTINATION ${YARP_STATIC_PLUGINS_INSTALL_DIR}
YARP_INI DESTINATION ${YARP_PLUGIN_MANIFESTS_INSTALL_DIR}
)

It is then possible to modify the connection in the client to use the new portmonitor

if (!yarp.connect("/demo/client", "/demo/server", "tcp++send.portmonitor+type.dll+file.demo_monitor")) {

In this way, the client will send a message to the /monitor port for every command sent or reply received. The name of the monitor port can be changed by passing +monitor.<monitor port> option to the carrier, for example

if (!yarp.connect("/demo/client", "/demo/server", "tcp++send.portmonitor+type.dll+file.demo_monitor+monitor./demo/monitor")) {

Using yarp rpc or custom clients

The same thing can be done also running yarp rpc in client mode. This is usually useless, but it can be helpful for debugging. Also the same method can be used if the client is written manually, and not using thrift,

yarp rpc --client /demo/yarprpc

and connecting it in a different terminal, using the right connection argument:

yarp connect /demo/yarprpc /demo/server tcp+send.portmonitor+type.dll+file.demo_monitor

If enabled, in order to monitor a connection using yarp rpc, it is also possible to use the generic version of the portmonitor (this does not work with thrift clients, but only with yarp rpc or other clients using yarp::os::Bottle and yarp::os::CommandBottle):

yarp connect /demo/yarprpc /demo/server tcp+send.portmonitor+type.dll+file.rpc_monitor