source: trunk/stoposclient.cpp @ 20

Last change on this file since 20 was 20, checked in by willem, 10 years ago

willem

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