]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/srfsh/srfsh.c
added EXEC_DEFAULT compile option for srfsh which is set by default.
[OpenSRF.git] / src / srfsh / srfsh.c
1 #include "srfsh.h"
2
3 int is_from_script = 0;
4
5 int main( int argc, char* argv[] ) {
6
7
8
9         /* --------------------------------------------- */
10         /* see if they have a .srfsh.xml in their home directory */
11         char* home = getenv("HOME");
12         int l = strlen(home) + 36;
13         char fbuf[l];
14         memset(fbuf, 0, l);
15         sprintf(fbuf,"%s/.srfsh.xml",home);
16
17         if(!access(fbuf, R_OK)) {
18                 if( ! osrf_system_bootstrap_client(fbuf) ) 
19                         fatal_handler( "Unable to bootstrap client for requests");
20
21         } else {
22                 fatal_handler( "No Config file found at %s", fbuf );
23         }
24
25         if(argc > 1) {
26                 /* for now.. the first arg is used as a script file for processing */
27                 int f;
28                 if( (f = open(argv[1], O_RDONLY)) == -1 )
29                         fatal_handler("Unable to open file %s for reading, exiting...", argv[1]);
30
31                 if(dup2(f, STDIN_FILENO) == -1)
32                         fatal_handler("Unable to duplicate STDIN, exiting...");
33
34                 close(f);
35                 is_from_script = 1;
36         }
37                 
38         /* --------------------------------------------- */
39         load_history();
40
41
42         client = osrf_system_get_transport_client();
43
44         /* main process loop */
45         char* request;
46         while((request=readline(prompt))) {
47
48                 if( !strcmp(request, "exit") || !strcmp(request,"quit")) 
49                         break; 
50
51                 char* req_copy = strdup(request);
52
53                 parse_request( req_copy ); 
54                 if( request && strlen(request) > 1 ) {
55                         add_history(request);
56                 }
57
58                 free(request);
59                 free(req_copy);
60         }
61
62         if(history_file != NULL )
63                 write_history(history_file);
64         free(request);
65         client_disconnect( client );
66         client_free( client );  
67         config_reader_free();   
68         log_free();
69                 
70         return 0;
71 }
72
73 void sig_child_handler( int s ) {
74         child_dead = 1;
75 }
76
77 /*
78 void sig_int_handler( int s ) {
79         printf("\n");
80         caught_sigint = 1;
81         signal(SIGINT,sig_int_handler);
82 }
83 */
84
85 int load_history() {
86
87         char* home = getenv("HOME");
88         int l = strlen(home) + 24;
89         char fbuf[l];
90
91         memset(fbuf, 0, l);
92         sprintf(fbuf,"%s/.srfsh_history",home);
93         history_file = strdup(fbuf);
94
95         if(!access(history_file, W_OK | R_OK )) {
96                 history_length = 999;
97                 read_history(history_file);
98         }
99         return 1;
100 }
101
102
103 int parse_error( char* words[] ) {
104
105         if( ! words )
106                 return 0;
107
108
109         int i = 0;
110         char* current;
111         char buffer[256];
112         memset(buffer, 0, 256);
113         while( (current=words[i++]) ) {
114                 strcat(buffer, current);
115                 strcat(buffer, " ");
116         }
117         if( ! buffer || strlen(buffer) < 1 ) 
118                 printf("\n");
119
120         fprintf( stderr, "???: %s\n", buffer );
121         return 0;
122
123 }
124
125
126 int parse_request( char* request ) {
127
128         if( request == NULL )
129                 return 0;
130
131         int ret_val = 0;
132         int i = 0;
133         char* words[COMMAND_BUFSIZE]; 
134         memset(words,0,COMMAND_BUFSIZE);
135         char* req = request;
136
137         char* cur_tok = strtok( req, " " );
138
139         if( cur_tok == NULL )
140                 return 0;
141
142         while(cur_tok != NULL) {
143                 words[i++] = cur_tok;
144                 cur_tok = strtok( NULL, " " );
145         }
146
147
148         // not sure why (strtok?), but this is necessary
149         memset( words + i, 0, COMMAND_BUFSIZE - i );
150
151         /* pass off to the top level command */
152         if( !strcmp(words[0],"router") ) 
153                 ret_val = handle_router( words );
154
155         else if( !strcmp(words[0],"time") ) 
156                 ret_val = handle_time( words );
157
158         else if (!strcmp(words[0],"request"))
159                 ret_val = handle_request( words, 0 );
160
161         else if (!strcmp(words[0],"relay"))
162                 ret_val = handle_request( words, 1 );
163
164         else if (!strcmp(words[0],"help"))
165                 ret_val = print_help();
166
167         else if (!strcmp(words[0],"set"))
168                 ret_val = handle_set(words);
169
170         else if (!strcmp(words[0],"print"))
171                 ret_val = handle_print(words);
172
173         else if (!strcmp(words[0],"math_bench"))
174                 ret_val = handle_math(words);
175
176         else if (!strcmp(words[0],"introspect"))
177                 ret_val = handle_introspect(words);
178
179         else if (!strcmp(words[0],"login"))
180                 ret_val = handle_login(words);
181
182         else if (words[0][0] == '!')
183                 ret_val = handle_exec( words );
184
185         if(!ret_val) {
186                 #ifdef EXEC_DEFAULT
187                         return handle_exec( words );
188                 #else
189                         return parse_error( words );
190                 #endif
191         }
192
193         return 1;
194
195 }
196
197
198 int handle_introspect(char* words[]) {
199
200         if(words[1] && words[2]) {
201                 fprintf(stderr, "--> %s\n", words[1]);
202                 char buf[256];
203                 memset(buf,0,256);
204                 sprintf( buf, "request %s opensrf.system.method %s", words[1], words[2] );
205                 return parse_request( buf );
206
207         } else {
208         
209                 if(words[1]) {
210                         fprintf(stderr, "--> %s\n", words[1]);
211                         char buf[256];
212                         memset(buf,0,256);
213                         sprintf( buf, "request %s opensrf.system.method.all", words[1] );
214                         return parse_request( buf );
215                 }
216         }
217
218         return 0;
219 }
220
221
222 int handle_login( char* words[]) {
223
224         if( words[1] && words[2]) {
225
226                 char* username = words[1];
227                 char* password = words[2];
228
229                 char buf[256];
230                 memset(buf,0,256);
231
232                 char buf2[256];
233                 memset(buf2,0,256);
234
235                 sprintf( buf, 
236                                 "request open-ils.auth open-ils.auth.authenticate.init \"%s\"", username );
237                 parse_request(buf); 
238
239                 char* hash;
240                 if(last_result && last_result->_result_content) {
241                         object* r = last_result->_result_content;
242                         hash = r->string_data;
243                 } else return 0;
244
245
246                 char* pass_buf = md5sum(password);
247
248                 char both_buf[256];
249                 memset(both_buf,0,256);
250                 sprintf(both_buf,"%s%s",hash, pass_buf);
251
252                 char* mess_buf = md5sum(both_buf);
253
254                 sprintf( buf2,
255                                 "request open-ils.auth open-ils.auth.authenticate.complete \"%s\", \"%s\", \"opac\"", 
256                                 username, mess_buf );
257
258                 free(pass_buf);
259                 free(mess_buf);
260
261                 parse_request( buf2 );
262
263                 login_session = strdup(last_result->_result_content->string_data);
264
265                 printf("Login Session: %s\n", login_session );
266                 
267                 return 1;
268
269         }
270
271         return 0;
272 }
273
274 char* md5sum( char* text ) {
275
276         struct md5_ctx ctx;
277         unsigned char digest[16];
278
279         MD5_start (&ctx);
280
281         int i;
282         for ( i=0 ; i != strlen(text) ; i++ )
283                 MD5_feed (&ctx, text[i]);
284
285         MD5_stop (&ctx, digest);
286
287         char buf[16];
288         memset(buf,0,16);
289
290         char final[256];
291         memset(final,0,256);
292
293         for ( i=0 ; i<16 ; i++ ) {
294                 sprintf(buf, "%02x", digest[i]);
295                 strcat( final, buf );
296         }
297
298         return strdup(final);
299
300 }
301
302
303 int handle_set( char* words[]) {
304
305         char* variable;
306         if( (variable=words[1]) ) {
307
308                 char* val;
309                 if( (val=words[2]) ) {
310
311                         if(!strcmp(variable,"pretty_print")) {
312                                 if(!strcmp(val,"true")) {
313                                         pretty_print = 1;
314                                         printf("pretty_print = true\n");
315                                         return 1;
316                                 } 
317                                 if(!strcmp(val,"false")) {
318                                         pretty_print = 0;
319                                         printf("pretty_print = false\n");
320                                         return 1;
321                                 } 
322                         }
323                 }
324         }
325
326         return 0;
327 }
328
329
330 int handle_print( char* words[]) {
331
332         char* variable;
333         if( (variable=words[1]) ) {
334                 if(!strcmp(variable,"pretty_print")) {
335                         if(pretty_print) {
336                                 printf("pretty_print = true\n");
337                                 return 1;
338                         } else {
339                                 printf("pretty_print = false\n");
340                                 return 1;
341                         }
342                 }
343
344                 if(!strcmp(variable,"login")) {
345                         printf("login session = %s\n", login_session );
346                         return 1;
347                 }
348
349         }
350         return 0;
351 }
352
353 int handle_router( char* words[] ) {
354
355         if(!client)
356                 return 1;
357
358         int i;
359
360         if( words[1] ) { 
361                 if( !strcmp(words[1],"query") ) {
362                         
363                         if( words[2] && !strcmp(words[2],"servers") ) {
364                                 for(i=3; i < COMMAND_BUFSIZE - 3 && words[i]; i++ ) {   
365                                         router_query_servers( words[i] );
366                                 }
367                                 return 1;
368                         }
369                         return 0;
370                 }
371                 return 0;
372         }
373         return 0;
374 }
375
376
377 int handle_exec(char* words[]) {
378
379         if(!words[0]) return 0;
380
381         if( words[0] && words[0][0] == '!') {
382                 int len = strlen(words[0]);
383                 char command[len];
384                 memset(command,0,len);
385         
386                 int i; /* chop out the ! */
387                 for( i=1; i!= len; i++) {
388                         command[i-1] = words[0][i];
389                 }
390         
391                 free(words[0]);
392                 words[0] = strdup(command);
393         }
394
395         signal(SIGCHLD,sig_child_handler);
396
397         if(fork()) {
398
399                 waitpid(-1, 0, 0);
400                 if(child_dead) {
401                         signal(SIGCHLD,sig_child_handler);
402                         child_dead = 0;
403                 }
404
405         } else {
406                 execvp( words[0], words );
407                 exit(0);
408         }
409         return 1;
410 }
411
412
413 int handle_request( char* words[], int relay ) {
414
415         if(!client)
416                 return 1;
417
418         if(words[1]) {
419                 char* server = words[1];
420                 char* method = words[2];
421                 int i;
422                 growing_buffer* buffer = NULL;
423                 if(!relay) {
424                         buffer = buffer_init(128);
425                         buffer_add(buffer, "[");
426                         for(i = 3; words[i] != NULL; i++ ) {
427                                 /* removes trailing semicolon if user accidentally enters it */
428                                 if( words[i][strlen(words[i])-1] == ';' )
429                                         words[i][strlen(words[i])-1] = '\0';
430                                 buffer_add( buffer, words[i] );
431                                 buffer_add(buffer, " ");
432                         }
433                         buffer_add(buffer, "]");
434                 }
435
436                 return send_request( server, method, buffer, relay );
437         } 
438
439         return 0;
440 }
441
442 int send_request( char* server, 
443                 char* method, growing_buffer* buffer, int relay ) {
444         if( server == NULL || method == NULL )
445                 return 0;
446
447         object* params = NULL;
448         if( !relay ) {
449                 if( buffer != NULL && buffer->n_used > 0 ) 
450                         params = json_parse_string(buffer->buf);
451         } else {
452                 if(!last_result || ! last_result->_result_content) { 
453                         printf("We're not going to call 'relay' with no result params\n");
454                         return 1;
455                 }
456                 else {
457                         object* o = new_object(NULL);
458                         o->push(o, last_result->_result_content );
459                         params = o;
460                 }
461         }
462
463
464         if(buffer->n_used > 0 && params == NULL) {
465                 fprintf(stderr, "JSON error detected, not executing\n");
466                 return 1;
467         }
468
469         osrf_app_session* session = osrf_app_client_session_init(server);
470
471         if(!osrf_app_session_connect(session)) {
472                 warning_handler( "Unable to connect to remote service %s\n", server );
473                 return 1;
474         }
475
476         double start = get_timestamp_millis();
477         //int req_id = osrf_app_session_make_request( session, params, method, 1, NULL );
478         int req_id = osrf_app_session_make_req( session, params, method, 1, NULL );
479
480
481         osrf_message* omsg = osrf_app_session_request_recv( session, req_id, 60 );
482         debug_handler("srfsh0");
483
484
485         if(!omsg) 
486                 printf("\nReceived no data from server\n");
487         
488         
489         signal(SIGPIPE, SIG_IGN);
490
491         FILE* less; 
492         if(!is_from_script) less = popen( "less -EX", "w");
493         else less = stdout;
494
495         if( less == NULL ) { less = stdout; }
496
497         growing_buffer* resp_buffer = buffer_init(4096);
498
499         while(omsg) {
500
501                 if(omsg->_result_content) {
502
503                         debug_handler("srfsh1");
504                         osrf_message_free(last_result);
505                         last_result = omsg;
506
507                         char* content;
508
509                         if( pretty_print && omsg->_result_content ) {
510                                 char* j = object_to_json(omsg->_result_content);
511                                 content = json_printer(j); 
512                                 free(j);
513                         } else
514                                 content = object_get_string(omsg->_result_content);
515
516                         debug_handler("srfsh2");
517
518                         buffer_add( resp_buffer, "\nReceived Data: " ); 
519                         buffer_add( resp_buffer, content );
520                         buffer_add( resp_buffer, "\n" );
521                         free(content);
522
523                 } else {
524
525                         buffer_add( resp_buffer, "\nReceived Exception:\nName: " );
526                         buffer_add( resp_buffer, omsg->status_name );
527                         buffer_add( resp_buffer, "\nStatus: " );
528                         buffer_add( resp_buffer, omsg->status_text );
529                         buffer_add( resp_buffer, "\nStatus: " );
530                         char code[16];
531                         memset(code, 0, 16);
532                         sprintf( code, "%d", omsg->status_code );
533                         buffer_add( resp_buffer, code );
534                 }
535
536
537                 omsg = osrf_app_session_request_recv( session, req_id, 5 );
538
539         }
540
541         double end = get_timestamp_millis();
542
543         fprintf( less, resp_buffer->buf );
544         buffer_free( resp_buffer );
545         fprintf( less, "\n------------------------------------\n");
546         if( osrf_app_session_request_complete( session, req_id ))
547                 fprintf(less, "Request Completed Successfully\n");
548
549
550         fprintf(less, "Request Time in seconds: %.3f\n", end - start );
551         fprintf(less, "------------------------------------\n");
552
553         pclose(less); 
554
555         osrf_app_session_request_finish( session, req_id );
556         osrf_app_session_disconnect( session );
557         osrf_app_session_destroy( session );
558
559
560         return 1;
561
562
563 }
564
565 int handle_time( char* words[] ) {
566
567         if( ! words[1] ) {
568
569                 char buf[36];
570                 memset(buf,0,36);
571                 get_timestamp(buf);
572                 printf( "%s\n", buf );
573                 return 1;
574         }
575
576         if( words[1] ) {
577                 time_t epoch = (time_t)atoi( words[1] );
578                 char* localtime = strdup( ctime( &epoch ) );
579                 printf( "%s => %s", words[1], localtime );
580                 free(localtime);
581                 return 1;
582         }
583
584         return 0;
585
586 }
587
588                 
589
590 int router_query_servers( char* router_server ) {
591
592         if( ! router_server || strlen(router_server) == 0 ) 
593                 return 0;
594
595         char rbuf[256];
596         memset(rbuf,0,256);
597         sprintf(rbuf,"router@%s/router", router_server );
598                 
599         transport_message* send = 
600                 message_init( "servers", NULL, NULL, rbuf, NULL );
601         message_set_router_info( send, NULL, NULL, NULL, "query", 0 );
602
603         client_send_message( client, send );
604         message_free( send );
605
606         transport_message* recv = client_recv( client, -1 );
607         if( recv == NULL ) {
608                 fprintf(stderr, "NULL message received from router\n");
609                 return 1;
610         }
611         
612         printf( 
613                         "---------------------------------------------------------------------------------\n"
614                         "Received from 'server' query on %s\n"
615                         "---------------------------------------------------------------------------------\n"
616                         "original reg time | latest reg time | last used time | class | server\n"
617                         "---------------------------------------------------------------------------------\n"
618                         "%s"
619                         "---------------------------------------------------------------------------------\n"
620                         , router_server, recv->body );
621
622         message_free( recv );
623         
624         return 1;
625 }
626                 
627 int print_help() {
628
629         printf(
630                         "---------------------------------------------------------------------------------\n"
631                         "Commands:\n"
632                         "---------------------------------------------------------------------------------\n"
633                         "help                   - Display this message\n"
634                         "!<command> [args] - Forks and runs the given command in the shell\n"
635                         "time                   - Prints the current time\n"                                    
636                         "time <timestamp>       - Formats seconds since epoch into readable format\n"   
637                         "set <variable> <value> - set a srfsh variable (e.g. set pretty_print true )\n"
638                         "print <variable>               - Displays the value of a srfsh variable\n"
639                         "---------------------------------------------------------------------------------\n"
640
641                         "router query servers <server1 [, server2, ...]>\n"
642                         "       - Returns stats on connected services\n"
643                         "\n"
644                         "\n"
645                         "request <service> <method> [ <json formatted string of params> ]\n"
646                         "       - Anything passed in will be wrapped in a json array,\n"
647                         "               so add commas if there is more than one param\n"
648                         "\n"
649                         "\n"
650                         "relay <service> <method>\n"
651                         "       - Performs the requested query using the last received result as the param\n"
652                         "\n"
653                         "\n"
654                         "math_bench <num_batches> [0|1|2]\n"
655                         "       - 0 means don't reconnect, 1 means reconnect after each batch of 4, and\n"
656                         "                2 means reconnect after every request\n"
657                         "\n"
658                         "introspect <service>\n"
659                         "       - prints the API for the service\n"
660                         "\n"
661                         "\n"
662                         "---------------------------------------------------------------------------------\n"
663                         " Commands for Open-ILS\n"
664                         "---------------------------------------------------------------------------------\n"
665                         "login <username> <password>\n"
666                         "       -       Logs into the 'server' and displays the session id\n"
667                         "       - To view the session id later, enter: print login\n"
668                         "---------------------------------------------------------------------------------\n"
669                         "\n"
670                         "\n"
671                         "Note: long output is piped through 'less'.  To search in 'less', type: /<search>\n"
672                         "---------------------------------------------------------------------------------\n"
673                         "\n"
674                         );
675
676         return 1;
677 }
678
679
680
681 char* tabs(int count) {
682         growing_buffer* buf = buffer_init(24);
683         int i;
684         for(i=0;i!=count;i++)
685                 buffer_add(buf, "   ");
686
687         char* final = buffer_data( buf );
688         buffer_free( buf );
689         return final;
690 }
691
692 char* json_printer( char* string ) {
693
694         growing_buffer* buf = buffer_init(64);
695         int i;
696         int tab_var = 0;
697         for(i=0; i!= strlen(string); i++) {
698
699                 if( string[i] == '{' ) {
700
701                         buffer_add(buf, "\n");
702                         char* tab = tabs(tab_var);
703                         buffer_add(buf, tab);
704                         free(tab);
705                         buffer_add( buf, "{");
706                         tab_var++;
707                         buffer_add( buf, "\n" );        
708                         tab = tabs(tab_var);
709                         buffer_add( buf, tab ); 
710                         free(tab);
711
712                 } else if( string[i] == '[' ) {
713
714                         buffer_add(buf, "\n");
715                         char* tab = tabs(tab_var);
716                         buffer_add(buf, tab);
717                         free(tab);
718                         buffer_add( buf, "[");
719                         tab_var++;
720                         buffer_add( buf, "\n" );        
721                         tab = tabs(tab_var);
722                         buffer_add( buf, tab ); 
723                         free(tab);
724
725                 } else if( string[i] == '}' ) {
726
727                         tab_var--;
728                         buffer_add(buf, "\n");
729                         char* tab = tabs(tab_var);
730                         buffer_add(buf, tab);
731                         free(tab);
732                         buffer_add( buf, "}");
733                         buffer_add( buf, "\n" );        
734                         tab = tabs(tab_var);
735                         buffer_add( buf, tab ); 
736                         free(tab);
737
738                 } else if( string[i] == ']' ) {
739
740                         tab_var--;
741                         buffer_add(buf, "\n");
742                         char* tab = tabs(tab_var);
743                         buffer_add(buf, tab);
744                         free(tab);
745                         buffer_add( buf, "]");
746                         buffer_add( buf, "\n" );        
747                         tab = tabs(tab_var);
748                         buffer_add( buf, tab ); 
749                         free(tab);
750
751                 } else if( string[i] == ',' ) {
752
753                         buffer_add( buf, ",");
754                         buffer_add( buf, "\n" );        
755                         char* tab = tabs(tab_var);
756                         buffer_add(buf, tab);
757                         free(tab);
758
759                 } else {
760
761                         char b[2];
762                         b[0] = string[i];
763                         b[1] = '\0';
764                         buffer_add( buf, b ); 
765                 }
766
767         }
768
769         char* result = buffer_data(buf);
770         buffer_free(buf);
771         return result;
772
773 }
774
775 int handle_math( char* words[] ) {
776         if( words[1] && words[2] ) 
777                 return do_math( atoi(words[1]), atoi(words[2]) );
778         return 0;
779 }
780
781
782 int do_math( int count, int style ) {
783
784         osrf_app_session* session = osrf_app_client_session_init(  "opensrf.math" );
785
786         object* params = json_parse_string("[]");
787         params->push(params,new_object("1"));
788         params->push(params,new_object("2"));
789
790         char* methods[] = { "add", "sub", "mult", "div" };
791         char* answers[] = { "\"3\"", "\"-1\"", "\"2\"", "\"0.5\"" };
792
793         float times[ count * 4 ];
794         memset(times,0,count*4);
795
796         int k;
797         for(k=0;k!=100;k++) {
798                 if(!(k%10)) 
799                         fprintf(stderr,"|");
800                 else
801                         fprintf(stderr,".");
802         }
803
804         fprintf(stderr,"\n\n");
805
806         int running = 0;
807         int i;
808         for(i=0; i!= count; i++) {
809
810                 int j;
811                 for(j=0; j != 4; j++) {
812
813                         ++running;
814                         struct timeb t1;
815                         struct timeb t2;
816
817                         ftime(&t1);
818                         //int req_id = osrf_app_session_make_request( session, params, methods[j], 1, NULL );
819                         int req_id = osrf_app_session_make_req( session, params, methods[j], 1, NULL );
820
821                         osrf_message* omsg = osrf_app_session_request_recv( session, req_id, 5 );
822
823                         ftime(&t2);
824
825                         double start    = ( (int)t1.time        + ( ((float)t1.millitm) / 1000 ) );
826                         double end              = ( (int)t2.time        + ( ((float)t2.millitm) / 1000 ) );
827
828                         times[(4*i) + j] = end - start;
829
830                         if(omsg) {
831         
832                                 if(omsg->_result_content) {
833                                         char* jsn = object_to_json(omsg->_result_content);
834                                         if(!strcmp(jsn, answers[j]))
835                                                 fprintf(stderr, "+");
836                                         else
837                                                 fprintf(stderr, "\n![%s] - should be %s\n", jsn, answers[j] );
838                                         free(jsn);
839                                 }
840
841
842                                 osrf_message_free(omsg);
843                 
844                         } else { fprintf( stderr, "\nempty message for tt: %d\n", req_id ); }
845
846                         osrf_app_session_request_finish( session, req_id );
847
848                         if(style == 2)
849                                 osrf_app_session_disconnect( session );
850
851                         if(!(running%100))
852                                 fprintf(stderr,"\n");
853                 }
854
855                 if(style==1)
856                         osrf_app_session_disconnect( session );
857         }
858
859         osrf_app_session_destroy( session );
860         free_object(params);
861
862         int c;
863         float total = 0;
864         for(c=0; c!= count*4; c++) 
865                 total += times[c];
866
867         float avg = total / (count*4); 
868         fprintf(stderr, "\n      Average round trip time: %f\n", avg );
869
870         return 1;
871 }