clang-tags
C/C++ source code indexing tool based on libclang
 All Classes Functions Variables Typedefs Groups Pages
request.hxx
1 #include <json/json.h>
2 
3 #include <iostream>
4 #include <sstream>
5 #include <iomanip>
6 #include <map>
7 #include <vector>
8 
90 namespace Request {
97  class KeyParserBase {
98  public:
103  KeyParserBase (std::string name)
104  : name_ (name),
105  required_ (false)
106  {}
107 
108  // Destructor
109  virtual ~KeyParserBase () {}
110 
115  const std::string & name () const {
116  return name_;
117  }
118 
131  void display (std::ostream & cout) const {
132  cout << " " << name_ << " " << metavar_ << std::endl;
133 
134  if (description_ != "")
135  cout << " " << description_ << std::endl;
136 
137  if (isVector())
138  cout << " multiple values allowed" << std::endl;
139 
140  if (default_ != "")
141  cout << " default: " << default_ << std::endl;
142 
143  if (required_)
144  cout << " required" << std::endl;
145 
146  cout << std::endl;
147  }
148 
163  KeyParserBase * metavar (std::string metavar) {
164  metavar_ = metavar;
165  return this;
166  }
167 
180  description_ = description;
181  return this;
182  }
183 
196  KeyParserBase * required (bool req = true) {
197  required_ = req;
198  return this;
199  }
200 
211  virtual bool isVector () const {
212  return false;
213  }
214 
223  virtual void parse (std::istream & cin) = 0;
224 
231  virtual void set (const Json::Value & json) = 0;
232 
233  protected:
238  std::string default_;
239 
240  private:
241  const std::string name_;
242  std::string description_;
243  std::string metavar_;
244  bool required_;
245  };
246 
247  template <typename T>
248  void setValue (const Json::Value & json, T & destination) {
249  std::istringstream iss (json.asString());
250  iss >> destination;
251  }
252 
261  template <typename T>
262  class Key : public KeyParserBase {
263  public:
272  Key (std::string name, T & destination)
273  : KeyParserBase (name),
274  destination_ (destination)
275  {
276  std::ostringstream defaultStr;
277  defaultStr << std::boolalpha << destination;
278  default_ = defaultStr.str();
279  }
280 
281  virtual void parse (std::istream & cin) {
282  cin >> std::boolalpha >> destination_;
283  }
284 
285  virtual void set (const Json::Value & json) {
286  setValue (json, destination_);
287  }
288 
289  private:
290  T & destination_;
291  };
292 
301  template <typename T>
302  class Key<std::vector<T> > : public KeyParserBase {
303  public:
305  typedef std::vector<T> Vector;
306 
313  Key (std::string name, Vector & destination)
314  : KeyParserBase (name),
315  destination_ (destination)
316  {
317  Json::Value defaults;
318 
319  auto it = destination.begin();
320  auto end = destination.end();
321  for ( ; it != end ; ++it) {
322  defaults.append (*it);
323  }
324 
325  default_ = Json::FastWriter().write (defaults);
326  }
327 
328  virtual bool isVector () const {
329  return true;
330  }
331 
332  virtual void parse (std::istream & cin) {
333  T val;
334  cin >> std::boolalpha >> val;
335  destination_.push_back (val);
336  }
337 
338  virtual void set (const Json::Value & json) {
339  destination_.resize (json.size());
340  for (int i = 0 ; i<json.size() ; ++i) {
341  setValue (json[i], destination_[i]);
342  }
343  }
344 
345  private:
346  Vector & destination_;
347  };
348 
349 
361  public:
367  CommandParser (std::string name, std::string description = "")
368  : prompt_ (name + "> "),
369  description_ (description),
370  name_ (name)
371  { }
372 
373  virtual ~CommandParser () {
374  auto it = keys_.begin();
375  auto end = keys_.end();
376  for ( ; it != end ; ++it) {
377  delete (it->second);
378  }
379  }
380 
392  void parse (std::istream & cin, std::ostream & cout, bool echo = false) {
393  defaults();
394  do {
395  cout << prompt_ << std::flush;
396  std::string line;
397  std::getline (cin, line);
398 
399  if (echo) {
400  cout << line << std::endl;
401  }
402 
403  if (line == "") {
404  break;
405  }
406 
407  std::istringstream input (line);
408  std::string key;
409  input >> key;
410 
411  KeyMap::const_iterator it = keys_.find(key);
412  if (it != keys_.end()) {
413  it->second->parse (input);
414  } else {
415  cout << "Unknown key: `" << key << "'" << std::endl;
416  }
417 
418  } while (! cin.eof());
419  run (cout);
420  }
421 
433  void parseJson (const Json::Value & request, std::ostream & cout) {
434  defaults();
435 
436  auto it = keys_.begin();
437  auto end = keys_.end();
438  for ( ; it != end ; ++it){
439  Json::Value arg = request[it->first];
440  if (! arg.isNull()) {
441  it->second->set (arg);
442  }
443  }
444 
445  run(cout);
446  }
447 
448  protected:
453  const std::string & name () {
454  return name_;
455  }
456 
463  void setDescription (std::string description) {
464  description_ = description;
465  }
466 
471  virtual void defaults () {}
472 
480  virtual void run (std::ostream & cout) = 0;
481 
489  keys_[key->name()] = (key);
490  return *this;
491  }
492 
495  std::string prompt_;
496 
497  private:
509  void help (std::ostream & cout) const {
510  cout << description_ << std::endl
511  << std::endl
512  << "Arguments:" << std::endl;
513  auto it = keys_.begin();
514  auto end = keys_.end();
515  for ( ; it != end ; ++it) {
516  it->second->display(cout);
517  }
518  }
519 
528  void display (std::ostream & cout) {
529  cout << std::setw(20) << std::left << name_
530  << " " << description_ << std::endl;
531  }
532 
533  typedef std::map<std::string, KeyParserBase*> KeyMap;
534 
535  std::string description_;
536  const std::string name_;
537  KeyMap keys_;
538 
539  friend class Parser;
540  };
541 
549  class Parser {
550  public:
555  Parser (std::string description = "")
556  : description_ (description),
557  echo_ (false)
558  { }
559 
560  ~Parser () {
561  auto it = commands_.begin();
562  auto end = commands_.end();
563  for ( ; it != end ; ++it) {
564  delete it->second;
565  }
566  }
567 
577  Parser & prompt (std::string p) {
578  prompt_ = p;
579  return *this;
580  }
581 
592  Parser & echo (bool activate = true) {
593  echo_ = activate;
594  return *this;
595  }
596 
603  Parser & add (CommandParser * command) {
604  commands_[command->name()] = command;
605  return *this;
606  }
607 
615  void help (std::ostream & cout) {
616  cout << description_ << std::endl
617  << "Commands:" << std::endl
618  << " " << std::setw(20) << std::left << "help"
619  << " Display this help" << std::endl
620  << " " << std::setw(20) << std::left << "help COMMAND"
621  << " Display help about COMMAND" << std::endl;
622 
623  auto it = commands_.begin();
624  auto end = commands_.end();
625  for ( ; it != end ; ++it) {
626  cout << " ";
627  it->second->display(cout);
628  }
629  }
630 
637  void parse (std::istream & cin, std::ostream & cout) {
638  do {
639  cout << prompt_ << std::flush;
640 
641  std::string line;
642  std::getline (cin, line);
643 
644  if (echo_) {
645  cout << line << std::endl;
646  }
647 
648  if (line == "") {
649  continue;
650  }
651 
652  std::istringstream input (line);
653  std::string command;
654  input >> command;
655 
656  bool helpRequested = false;
657  if (command == "help") {
658  input >> command;
659  if (command == "help") {
660  help(cout);
661  continue;
662  } else {
663  helpRequested = true;
664  }
665  }
666 
667  CommandMap::const_iterator it = commands_.find (command);
668  if (it != commands_.end()) {
669  if (helpRequested)
670  it->second->help (cout);
671  else
672  it->second->parse (cin, cout, echo_);
673  } else {
674  cout << "Unknown command: `" << command << "'" << std::endl;
675  }
676 
677  } while (! cin.eof());
678  }
679 
688  void parseJson (std::istream & cin, std::ostream & cout, bool verbose=false) {
689  if (verbose)
690  std::cerr << "Receiving client request:" << std::endl;
691 
692  std::stringstream request;
693  while (true) {
694  std::string line;
695  std::getline (cin, line);
696  if (line == "")
697  break;
698 
699  if (verbose)
700  std::cerr << line << std::endl;
701 
702  request << line << std::endl;
703  }
704 
705  Json::Value json;
706  request >> json;
707 
708  if (verbose)
709  std::cerr << "Processing request... ";
710  cout << "Server response:" << std::endl << std::flush;
711 
712  std::string command = json["command"].asString();
713  CommandMap::const_iterator it = commands_.find (command);
714  if (it != commands_.end()) {
715  it->second->parseJson (json, cout);
716  } else {
717  cout << "Unknown command: `" << command << "'" << std::endl;
718  }
719 
720  if (verbose)
721  std::cerr << "done." << std::endl << std::endl;
722  }
723 
724  private:
725  typedef std::map<std::string, CommandParser*> CommandMap;
726  CommandMap commands_;
727  std::string description_;
728  std::string prompt_;
729  bool echo_;
730  };
731 
745  template <typename T>
746  Key<T>* key (std::string name, T & destination) {
747  return new Key<T> (name, destination);
748  }
749 }