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