Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oneway service request from the command line #477

Merged
merged 16 commits into from
Mar 13, 2024
24 changes: 16 additions & 8 deletions src/cmd/gz.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

//////////////////////////////////////////////////
Expand Down
14 changes: 8 additions & 6 deletions src/cmd/gz.hh
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,26 @@ 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().
/// E.g.: cmdServiceReq("/bar", "gz.msgs.StringMsg",
/// "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
Expand Down
32 changes: 31 additions & 1 deletion src/cmd/gz_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down
23 changes: 17 additions & 6 deletions src/cmd/service_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.");

Expand Down Expand Up @@ -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); });
}
Expand Down