source: trunk/stoposclient.cpp @ 22

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