RTC Toolkit 5.0.0
Loading...
Searching...
No Matches
clientLib.hpp
Go to the documentation of this file.
1
13#ifndef RTCTK_CLIENT_CLIENTLIB_HPP
14#define RTCTK_CLIENT_CLIENTLIB_HPP
15
20
21#include <boost/program_options.hpp>
22
23#include <chrono>
24#include <iostream>
25#include <thread>
26
27namespace rtctk::client {
28
29boost::program_options::variables_map ParseOptions(int argc, char* argv[]);
30
34template <typename CommandRequestorType = rtctk::componentFramework::CommandRequestor>
35int RunClient(int argc, char** argv) {
36 static_assert(
37 std::is_base_of_v<rtctk::componentFramework::CommandRequestor, CommandRequestorType>,
38 "'CommandRequestorType must extend 'rtctk::componentFramework::CommandRequestor'");
39 using namespace std;
40 using namespace rtctk::componentFramework;
41 using elt::mal::Uri;
42 using std::chrono::duration;
43 using std::chrono::duration_cast;
44 using std::chrono::milliseconds;
45 using std::chrono::seconds;
46
47 LogInitializer initializer;
48 LogConfigureTool("rtctkClient");
49 auto& logger = GetLogger("rtctk");
50
51 auto args = ParseOptions(argc, argv);
52 string cid = args["cid"].as<string>();
53 string cmd = args["cmd"].as<string>();
54 string cmd_arg = args["cmd_arg"].as<string>();
55 Uri sde = args["sde"].as<Uri>();
56 ServiceDiscovery serv_disc(sde, cid);
57
58 std::optional<milliseconds> timeout;
59 if (args.count("timeout")) {
60 timeout = duration_cast<milliseconds>(duration<double>(args["timeout"].as<double>()));
61 }
62
63 try {
64 if (cmd == "Listen") {
65 Uri subscribe_uri = serv_disc.GetPubSubEndpoint();
66 LOG4CPLUS_DEBUG(logger, "Subscribe URI is '" << subscribe_uri << "'.");
67
68 StateSubscriber subscriber(subscribe_uri,
69 [&](const taiclock::TaiClock::time_point timestamp,
70 const string& name,
71 const string& state) {
72 LOG4CPLUS_INFO(logger,
73 name << " changed state to: " << state);
74 });
75
76 while (true) {
77 this_thread::sleep_for(seconds(1));
78 }
79
80 } else {
81 Uri request_uri = serv_disc.GetReqRepEndpoint();
82 LOG4CPLUS_DEBUG(logger, "Request URI is '" << request_uri << "'.");
83
84 CommandRequestorType requestor(request_uri, timeout);
85 auto reply = requestor.SendCommandSync(cmd, cmd_arg);
86 cout << reply << endl;
87 }
88 } catch (const elt::mal::TimeoutException& e) {
89 LOG4CPLUS_ERROR(logger, "Request timed out.");
90 return EXIT_FAILURE;
91 } catch (const std::exception& e) {
92 LOG4CPLUS_FATAL(logger, e.what());
93 return EXIT_FAILURE;
94 } catch (...) {
95 LOG4CPLUS_FATAL(logger, "Unknown exception");
96 return EXIT_FAILURE;
97 }
98
99 return EXIT_SUCCESS;
100}
101
102boost::program_options::variables_map ParseOptions(int argc, char* argv[]) {
103 using namespace std;
104 namespace bpo = boost::program_options;
105 using elt::mal::Uri;
107 auto& logger = GetLogger("rtctk");
108
109 bpo::positional_options_description pos_opts_desc;
110 pos_opts_desc.add("cid", 1);
111 pos_opts_desc.add("cmd", 1);
112 pos_opts_desc.add("cmd_arg", -1);
113
114 bpo::options_description opts_desc("Options");
115 // clang-format off
116 opts_desc.add_options()
117 ("help,h", "Print help messages")
118 ("timeout,t", bpo::value<double>()->default_value(30.0), "timeout [sec]")
119 ("cid,i", bpo::value<string>(), "component identity")
120 ("cmd,c", bpo::value<string>(), "command name")
121 ("cmd_arg,a", bpo::value<string>()->default_value(""), "command arguments")
122 ("sde,s", bpo::value<Uri>()->default_value(Uri("consul://localhost:8500")),
123 "service discovery endpoint");
124 // clang-format on
125
126 try {
127 bpo::variables_map vm;
128
129 bpo::store(
130 bpo::command_line_parser(argc, argv).options(opts_desc).positional(pos_opts_desc).run(),
131 vm);
132
133 bpo::notify(vm);
134
135 if (vm.count("help")) {
136 cout << opts_desc << endl;
137 exit(EXIT_SUCCESS);
138 }
139 if (vm.count("cid")) {
140 LOG4CPLUS_DEBUG(logger, "Component identity is '" << vm["cid"].as<string>() << "'.");
141 } else {
142 LOG4CPLUS_FATAL(logger, "Component identity not specified !");
143 exit(EXIT_FAILURE);
144 }
145 if (vm.count("cmd")) {
146 LOG4CPLUS_DEBUG(logger, "Command is '" << vm["cmd"].as<string>() << "'.");
147 } else {
148 LOG4CPLUS_FATAL(logger, "Command name not specified !");
149 exit(EXIT_FAILURE);
150 }
151 if (vm.count("cmd_arg")) {
152 LOG4CPLUS_DEBUG(logger, "Command Arg is '" << vm["cmd_arg"].as<string>() << "'.");
153 }
154 if (vm.count("sde")) {
155 LOG4CPLUS_DEBUG(logger,
156 "Service Discovery Endpoint is '" << vm["sde"].as<Uri>() << "'.");
157 } else {
158 LOG4CPLUS_FATAL(logger, "Service Discovery Endpoint not specified !");
159 exit(EXIT_FAILURE);
160 }
161 if (vm.count("timeout")) {
162 LOG4CPLUS_DEBUG(logger,
163 "Request reply timeout is " << vm["timeout"].as<double>() << "s.");
164 }
165
166 return vm;
167
168 } catch (bpo::error& e) {
169 LOG4CPLUS_FATAL(logger, e.what() << endl << endl);
170 LOG4CPLUS_INFO(logger, opts_desc << endl);
171 exit(EXIT_FAILURE);
172 }
173}
174
175} // namespace rtctk::client
176
177#endif // RTCTK_CLIENT_CLIENTLIB_HPP
RAII class to clean-up logging without leaking memory.
Definition logger.hpp:28
Class that implements a very basic service discovery mechanism.
Definition serviceDiscovery.hpp:33
Class used to subscribe to state-changed-topic using MAL.
Definition stateSubscriber.hpp:41
Send commands using MAL.
Logging Support Library based on log4cplus.
Definition clientLib.hpp:27
int RunClient(int argc, char **argv)
Definition clientLib.hpp:35
boost::program_options::variables_map ParseOptions(int argc, char *argv[])
Definition clientLib.hpp:102
Definition commandReplier.cpp:22
log4cplus::Logger & GetLogger(const std::string &name="app")
Get handle to a specific logger.
Definition logger.cpp:193
Class that implements a very basic service discover mechanism.
Subscribes to stdif state topic via MAL.