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