From 3a5553afc82858a89963bb76375c0e16d9147ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ag=C3=BCero?= Date: Wed, 13 Mar 2024 12:30:30 +0100 Subject: [PATCH] Oneway service request from the command line (#477) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support request/advertise within the same process. Signed-off-by: Carlos Agüero --- src/cmd/gz.cc | 24 ++++++++++++++++-------- src/cmd/gz.hh | 14 ++++++++------ src/cmd/gz_TEST.cc | 32 +++++++++++++++++++++++++++++++- src/cmd/service_main.cc | 23 +++++++++++++++++------ 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/cmd/gz.cc b/src/cmd/gz.cc index 2e8a16004..68b843434 100644 --- a/src/cmd/gz.cc +++ b/src/cmd/gz.cc @@ -251,17 +251,25 @@ extern "C" void cmdServiceReq(const char *_service, Node node; bool result; - // Request the service. - bool executed = node.Request(_service, *req, _timeout, *rep, result); - if (executed) + if (!strcmp(_repType, "gz.msgs.Empty")) { - if (result) - std::cout << rep->DebugString() << std::endl; - else - std::cout << "Service call failed" << std::endl; + // One-way service. + node.Request(_service, *req, 1000, *rep, result); } else - std::cerr << "Service call timed out" << std::endl; + { + // Two-way service. + bool executed = node.Request(_service, *req, _timeout, *rep, result); + if (executed) + { + if (result) + std::cout << rep->DebugString() << std::endl; + else + std::cout << "Service call failed" << std::endl; + } + else + std::cerr << "Service call timed out" << std::endl; + } } ////////////////////////////////////////////////// diff --git a/src/cmd/gz.hh b/src/cmd/gz.hh index a48f63a3c..e9a827ebe 100644 --- a/src/cmd/gz.hh +++ b/src/cmd/gz.hh @@ -44,13 +44,15 @@ extern "C" void cmdServiceList(); /// E.g.: cmdTopicPub("/foo", "gz.msgs.StringMsg", /// "'data:\"Custom data\"'); extern "C" void cmdTopicPub(const char *_topic, - const char *_msgType, - const char *_msgData); + const char *_msgType, + const char *_msgData); /// \brief External hook to execute 'gz service -r' from the command line. /// \param[in] _service Service name. /// \param[in] _reqType Message type used in the request. /// \param[in] _repType Message type used in the response. +/// If "gz.msgs.Empty" is used, the request will be one-way +/// and _repType and _timeout will be ignored. /// \param[in] _timeout The request will timeout after '_timeout' ms. /// \param[in] _reqData Input data sent in the request. /// The format expected is the same used by Protobuf DebugString(). @@ -58,10 +60,10 @@ extern "C" void cmdTopicPub(const char *_topic, /// "gz.msgs.StringMsg", 1000, /// "'data:\"Custom data\"'); extern "C" void cmdServiceReq(const char *_service, - const char *_reqType, - const char *_repType, - const int _timeout, - const char *_reqData); + const char *_reqType, + const char *_repType, + const int _timeout, + const char *_reqData); extern "C" { /// \brief Enum used for specifing the message output format for functions diff --git a/src/cmd/gz_TEST.cc b/src/cmd/gz_TEST.cc index dd14fffcc..803a279fa 100644 --- a/src/cmd/gz_TEST.cc +++ b/src/cmd/gz_TEST.cc @@ -46,6 +46,13 @@ bool srvEcho(const msgs::Int32 &_req, msgs::Int32 &_rep) return true; } +////////////////////////////////////////////////// +/// \brief Provide a one-way service. +void srvOneway(const msgs::StringMsg &_msg) +{ + g_topicCBStr = _msg.data(); +} + ////////////////////////////////////////////////// /// \brief Topic callback void topicCB(const msgs::StringMsg &_msg) @@ -324,7 +331,7 @@ TEST(gzTest, TopicPublish) } ////////////////////////////////////////////////// -/// \brief Check 'gz service -r' to request a service. +/// \brief Check 'gz service -r' to request a two-way service. TEST(gzTest, ServiceRequest) { transport::Node node; @@ -347,6 +354,29 @@ TEST(gzTest, ServiceRequest) ASSERT_EQ(output.cout, "data: " + value + "\n\n"); } +////////////////////////////////////////////////// +/// \brief Check 'gz service -r' to request a one-way service. +TEST(gzTest, ServiceOnewayRequest) +{ + g_topicCBStr = "bad_value"; + transport::Node node; + + // Advertise a service. + std::string service = "/oneway"; + EXPECT_TRUE(node.Advertise(service, srvOneway)); + + msgs::StringMsg msg; + msg.set_data("good_value"); + + // Check the 'gz service' oneway command. + auto output = custom_exec_str( + {"service", "-s", service, "--reqtype", "gz.msgs.StringMsg", + "--req", "data: \"good_value\""}); + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + EXPECT_EQ("good_value", g_topicCBStr); +} + ////////////////////////////////////////////////// /// \brief Check 'gz topic -e' running the publisher on a separate process. TEST(gzTest, TopicEcho) diff --git a/src/cmd/service_main.cc b/src/cmd/service_main.cc index 063e00f5f..c159c7750 100644 --- a/src/cmd/service_main.cc +++ b/src/cmd/service_main.cc @@ -68,9 +68,20 @@ void runServiceCommand(const ServiceOptions &_opt) cmdServiceInfo(_opt.service.c_str()); break; case ServiceCommand::kServiceReq: - cmdServiceReq(_opt.service.c_str(), - _opt.reqType.c_str(), _opt.repType.c_str(), - _opt.timeout, _opt.reqData.c_str()); + if (_opt.repType.empty()) + { + // One-way service request. + cmdServiceReq(_opt.service.c_str(), + _opt.reqType.c_str(), "gz.msgs.Empty", + 0, _opt.reqData.c_str()); + } + else + { + // Two-way service request. + cmdServiceReq(_opt.service.c_str(), + _opt.reqType.c_str(), _opt.repType.c_str(), + _opt.timeout, _opt.reqData.c_str()); + } break; case ServiceCommand::kNone: default: @@ -93,6 +104,8 @@ void addServiceFlags(CLI::App &_app) opt->repType, "Type of a response."); auto timeoutOpt = _app.add_option("--timeout", opt->timeout, "Timeout in milliseconds."); + repTypeOpt = repTypeOpt->needs(timeoutOpt); + timeoutOpt = timeoutOpt->needs(repTypeOpt); auto command = _app.add_option_group("command", "Command to be executed."); @@ -123,9 +136,7 @@ the same used by Protobuf DebugString(). E.g.: --req 'data: "Hello"' )") ->needs(serviceOpt) - ->needs(reqTypeOpt) - ->needs(repTypeOpt) - ->needs(timeoutOpt); + ->needs(reqTypeOpt); _app.callback([opt](){runServiceCommand(*opt); }); }