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