source: trunk/stoposclient.cpp

Last change on this file was 24, checked in by willem, 8 years ago

willem

File size: 11.5 KB
Line 
1
2/*
3   Copyright 2013 Willem Vermin, SURFsara
4
5   Licensed under the Apache License, Version 2.0 (the "License");
6   you may not use this file except in compliance with the License.
7   You may obtain a copy of the License at
8
9       http://www.apache.org/licenses/LICENSE-2.0
10
11   Unless required by applicable law or agreed to in writing, software
12   distributed under the License is distributed on an "AS IS" BASIS,
13   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   See the License for the specific language governing permissions and
15   limitations under the License.
16 */
17#include <iostream>
18#include <vector>
19#include <stdlib.h>
20#include <unistd.h>
21#include <getopt.h>
22#include <fstream>
23#include "wrequest.h"
24#include "shellenv.h"
25#include "stopos.h"
26
27struct returnvalue
28{
29  std::string msg;
30  std::string key;
31  std::string comm;
32  std::string count;
33  std::string present;
34  std::string present0;
35  std::string value;
36
37  void parse(std::string &s)
38  {
39    // we expect somewhere in the output of the server a line like
40    // STOPOS:/OK/123/beautiful
41    // OK        -> msg
42    // 123       -> key
43    // 1         -> comm
44    // beautiful -> value
45    //
46    // OK, 123 and beautiful are hex coded
47    this->msg       = "";
48    this->key       = "";
49    this->comm      = "0";
50    this->count     = "0";
51    this->present   = "0";
52    this->present0  = "0";
53    this->value     = "";
54
55    size_t p = s.find("STOPOS:");
56    if (p == s.npos)
57    {
58      this->msg="Error: stopos server not running.";
59      return;
60    }
61
62    size_t q = s.find('\n',p+1);
63    std::string l = s.substr(p,q-p);
64    std::vector <std::string> v;
65
66    split(v,l,outsep);
67    for (unsigned int i=1; i<v.size(); i++)
68    {
69      switch (i)
70      {
71        case 1: this->msg       = zhextostr(v[i]); break;
72        case 2: this->key       = zhextostr(v[i]); break;
73        case 3: this->comm      = zhextostr(v[i]); break;
74        case 4: this->count     = zhextostr(v[i]); break;
75        case 5: this->present   = zhextostr(v[i]); break;
76        case 6: this->present0  = zhextostr(v[i]); break;
77        case 7: this->value     = zhextostr(v[i]); break;
78      }
79      // special case for key: if key == "", we try to take
80      // it from the environment.
81      if (trim(this->key) == "")
82        this->key = envtostr("STOPOS_KEY");
83    }
84  }
85};
86
87void usage()
88{
89  std::cerr << "Usage:" << std::endl;
90
91  std::cerr << program_name << " -h,--help"                           << std::endl;
92  std::cerr << program_name << " -v,--version"                        << std::endl;
93  std::cerr << program_name << " create [-p,--pool POOL]"             << std::endl;
94  std::cerr << program_name << " purge  [-p,--pool POOL]"             << std::endl;
95  std::cerr << program_name << " pools"                               << std::endl;
96  std::cerr << program_name << " add    [-p,--pool POOL] [FILENAME]"  << std::endl;
97  std::cerr << program_name << " next   [-p,--pool POOL] [-m,--mult]" << std::endl;
98  std::cerr << program_name << " remove [-p,--pool POOL] [KEY]"       << std::endl;
99  std::cerr << program_name << " status [-p,--pool POOL]"             << std::endl;
100  std::cerr << program_name << " dump   [-p,--pool POOL]"             << std::endl;
101  std::cerr << " -q,--quiet added to any command will reduce the ouput" << std::endl;
102  std::cerr << "Defaults:"                                            << std::endl;
103  std::cerr << "  POOL     : pool"                                    << std::endl;
104  std::cerr << "  FILENAME : standard input"                          << std::endl;
105
106  std::cerr << "Environment:"<<std::endl;
107  std::cerr << "   Defined by user:"<<std::endl;
108  std::cerr << "     STOPOS_POOL    : name of pool"<<std::endl;
109  std::cerr << "     STOPOS_KEY     : key"<<std::endl;
110  std::cerr << "   Defined by "<<program_name<<":"<<std::endl;
111  std::cerr << "     STOPOS_RC      : return message of all commands. OK == good" << std::endl;
112  std::cerr << "     STOPOS_VALUE   : result of 'next' or 'pools'"<<std::endl;
113  std::cerr << "     STOPOS_KEY     : result of 'next'"<<std::endl;
114  std::cerr << "     STOPOS_COUNT   : result of 'status'"<<std::endl;
115  std::cerr << "     STOPOS_PRESENT : result of 'status'"<<std::endl;
116  std::cerr << "     STOPOS_PRESENT0: result of 'status'"<<std::endl;
117
118
119
120}
121
122int handle_add(wrequest &w,const std::string &fname,returnvalue &r, const bool quiet)
123{
124  size_t number_of_lines=0;
125
126  bool read_from_stdin = 0;
127  int rc;
128  std::ifstream inp;
129  std::istream *pinp;
130  if(fname == "")  // read from stdin
131  {
132    read_from_stdin = 1;
133    pinp = &std::cin;
134  }
135  else
136  {
137    inp.open(fname.c_str());
138    if (!inp.is_open())
139    {
140      r.msg = "ERROR: Cannot open '"+fname+"'";
141      return 1;
142    }
143
144    number_of_lines = count_lines(inp);
145    pinp = &inp;
146  }
147  std::string line;
148  size_t n = 0;
149  w.set_command("add");
150  std::string body,header;
151
152  progress_bar bar;
153
154  while (getline(*pinp,line))
155  {
156    if (! quiet)
157    {
158      bool c;
159      std::string s;
160      if (read_from_stdin)
161        s = bar.show(n,c);
162      else
163        s = bar.show(n,(double)n/number_of_lines,c);
164      if (c)
165        std::cerr << '\r' << s;
166    }
167    if (line.size() > maxlinelength)
168    {
169      r.msg =  "Error: line length exeeds "+ NumberToString(maxlinelength);
170      break;
171    }
172    w.set_value(line);
173
174    for (int i=0; i<connect_error_retries; i++)
175    {
176      rc = w.send_message(body,header);
177      if (rc == 0) break;
178      sleep(1);
179    }
180    if (rc != 0)
181    {
182      r.msg = connect_error_msg;
183      return 1;
184    }
185
186    r.parse(body);
187    if (r.msg != "OK")
188      break;
189    n++;
190  }
191  if (! quiet)
192  {
193    bar.clear();
194    if (read_from_stdin)
195      std::cerr << '\r' << bar.show(n) << std::endl;
196    else
197      std::cerr << '\r' << bar.show(n,1.0) << std::endl;
198
199    std::cerr << program_name << ": Number of lines added = "<<n<<std::endl;
200  }
201  if (r.msg != "OK")
202    return 1;
203  return 0;
204}
205
206int main(int argc, char*argv[])
207{
208  wrequest w;
209 
210  int rc;
211
212  rc = w.read_config();
213  if (rc != 0 || w.get_config().size() != w.config_size)
214  {
215    std::cerr << "No valid config file found, creating it ..." << std::endl;
216    rc = w.write_config();
217    rc = rc | w.read_config();
218    if (rc != 0)
219    {
220      std::cerr << "Cannot write config file, exiting." << std::endl;
221      return 1;
222    }
223  }
224
225  bool addflag=0;
226  std::string inputfilename;
227  std::vector <std::string> parms;
228
229  static struct option long_options[] =
230  {
231    {"help",     0, 0, 'h'},
232    {"pool",     1, 0, 'p'},
233    {"version",  0, 0, 'v'},
234    {"multi",    0, 0, 'm'},
235    {"quiet",    0, 0, 'q'},
236    {0,          0, 0, 0}
237  };
238
239  // determine name of pool, in case it is not set on commandline
240
241  std::string pool = default_pool;
242  std::string p = envtostr("STOPOS_POOL");
243
244  if (p != "")
245    pool = p;
246
247  if (trim(w.get_pool()) != "")
248    pool = w.get_pool();
249
250  bool quiet = 0;
251
252  while(1)
253  {
254    int c = getopt_long(argc,argv,"-hp:vmq",long_options,0);
255    if (c == -1)
256    {
257      if (optind < argc)  // unexpected extra argument
258      {
259        std::cerr << program_name << ": Unexpected argument:" << argv[optind] << std::endl;
260        return 1;
261      }
262      break;
263    }
264    if ( c == '?' || c == ':' )
265    {
266      std::cerr << program_name << ": Invalid parameter, try "<< program_name<<" --help " <<std::endl;
267      return 1;
268    }
269    switch(c)
270    {
271      case 'h':
272        usage();
273        return 0;
274        break;
275      case 'p':
276        pool = optarg;
277        break;
278      case 'f':
279        inputfilename = optarg;
280        break;
281      case 'v':
282        std::cerr << program_version << std::endl;
283        return 0;
284        break;
285      case 'm':
286        w.set_multi("yes");
287        break;
288      case 'q':
289        quiet = 1;
290        break;
291      case 1:
292        parms.push_back(optarg);
293    }
294  }
295
296  w.set_pool(pool);
297  std::string serverurl=envtostr("STOPOS_SERVER_URL");
298  if (serverurl == "")
299    serverurl = SERVER_URL;
300  w.set_serverurl(serverurl);
301#ifdef DEFAULT_FLAT
302  std::string prot = "flat";
303#endif
304#ifdef DEFAULT_GDBM
305  std::string prot = "gdbm";
306#endif
307#ifdef DEFAULT_FILES
308  std::string prot = "files";
309#endif
310#ifdef DEFAULT_MYSQL
311  std::string prot = "mysql";
312#endif
313  std::string protenv;
314  protenv = envtostr("STOPOS_PROT");
315  if (protenv.size() !=0)
316    prot = protenv;
317  w.set_protocol(prot);
318  w.set_whoami(envtostr("USER"));
319
320  rc = 0;
321  returnvalue r;
322
323  if (parms.size() == 0)
324  {
325    std::cerr << program_name << ": No command given." << std::endl;
326    return 1;
327  }
328
329  std::string command = parms[0];
330
331  // only the remove and add commands can accept an extra parameter
332  //
333
334  if (parms.size() >1)
335    if (command !="remove" && command != "add")
336    {
337      std::cerr << program_name << ": Extraneous parameter:'"<<parms[1]<<"'."<<std::endl;
338      return 1;
339    }
340
341  bool count_set     = 0;
342  bool value_set     = 0;
343  bool committed_set = 0;
344  bool present_set   = 0;
345  bool present0_set  = 0;
346  bool key_set       = 0;
347  bool rc_set        = 0;
348
349  if(command == "create")
350  {
351    rc_set = 1;
352    w.set_command("create");
353  }
354  else if(command == "purge")
355  {
356    rc_set = 1;
357    w.set_command("purge");
358  }
359  else if(command == "status")
360  {
361    rc_set       = 1;
362    present_set  = 1;
363    present0_set = 1;
364    count_set    = 1;
365    w.set_command("status");
366  }
367  else if(command == "next")
368  {
369    rc_set        = 1;
370    value_set     = 1;
371    key_set       = 1;
372    committed_set = 1;
373    w.set_command("next");
374  }
375  else if(command == "dump")
376  {
377    rc_set        = 1;
378    value_set     = 1;
379    key_set       = 1;
380    committed_set = 1;
381    w.set_command("dump");
382  }
383  else if(command == "pools")
384  {
385    rc_set    = 1;
386    value_set = 1;
387    w.set_command("pools");
388  }
389  else if(command == "remove")
390  {
391    rc_set    = 1;
392    w.set_command("remove");
393    if (parms.size() < 2)
394    {
395      std::string a=envtostr("STOPOS_KEY");
396      if (a == "")
397      {
398        std::cerr << program_name << ": No key found, exit.\n";
399        return 1;
400      }
401      w.set_value(a);
402    }
403    else
404      w.set_value(parms[1]);
405  }
406  else if(command == "add")
407  {
408    rc_set  = 1;
409    key_set = 1;
410    addflag = 1;
411  }
412  else
413  {
414    std::cerr << program_name << ": Invalid command: '"<<command<<"'"<<std::endl;
415    return 1;
416  }
417
418  if(addflag)
419  {
420    if (parms.size() > 1)
421      inputfilename = parms[1];
422    rc |= handle_add(w,inputfilename,r,quiet);
423  }
424  else
425  {
426    std::string body,header;
427
428    for (int i=0; i<connect_error_retries; i++)
429    {
430      rc = w.send_message(body,header);
431      if (rc == 0) break;
432      sleep(1);
433    }
434    if (rc != 0)
435      r.msg = connect_error_msg;
436    else
437      r.parse(body);
438  }
439
440  int shelltype;
441
442  char *shell = getenv("SHELL");
443  std::string sh;
444  if (shell == 0)
445    sh = "bash";
446  else
447    sh = shell;
448
449  if (sh.find("csh") != sh.npos)
450    shelltype=SHELL_CSH;
451  else
452    shelltype = SHELL_SH;
453
454  if(rc_set)        std::cout << shellenv(r.msg,      "STOPOS_RC",        shelltype);
455  if(key_set)       std::cout << shellenv(r.key,      "STOPOS_KEY",       shelltype);
456  if(committed_set) std::cout << shellenv(r.comm,     "STOPOS_COMMITTED", shelltype);
457  if(count_set)     std::cout << shellenv(r.count,    "STOPOS_COUNT",     shelltype);
458  if(present_set)   std::cout << shellenv(r.present,  "STOPOS_PRESENT",   shelltype);
459  if(present0_set)  std::cout << shellenv(r.present0, "STOPOS_PRESENT0",  shelltype);
460  if(value_set)     std::cout << shellenv(r.value,    "STOPOS_VALUE",     shelltype);
461
462  if (command == "status" && r.msg == "OK" && ! quiet)
463  {
464    std::cerr << "lines added:           " << r.count    <<std::endl;
465    std::cerr << "lines present:         " << r.present  <<std::endl;
466    std::cerr << "lines never committed: " << r.present0 << std::endl;
467  }
468  else if (command == "pools" && ! quiet)
469  {
470    if(r.value.size()>0) std::cerr << r.value << std::endl;
471  }
472  if (r.msg != "OK" && ! quiet)
473  {
474    std::cerr << program_name<<": "<<r.msg << std::endl;
475    rc = 1;
476  }
477
478  return rc;
479}
Note: See TracBrowser for help on using the repository browser.