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