]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/srfsh/srfsh.c
added 'relay' which allows you to use the last received result as the param to
[OpenSRF.git] / src / srfsh / srfsh.c
1 #include "opensrf/transport_client.h"
2 #include "opensrf/generic_utils.h"
3 #include "opensrf/osrf_message.h"
4 #include "opensrf/osrf_app_session.h"
5 #include <time.h>
6
7 #include <signal.h>
8
9 #include <stdio.h>
10 #include <readline/readline.h>
11 #include <readline/history.h>
12
13
14 #define SRFSH_PORT 5222
15 #define COMMAND_BUFSIZE 12
16
17 /* shell prompt */
18 char* prompt = "srfsh# "; 
19
20 int child_dead = 0;
21
22 /* true if we're pretty printing json results */
23 int pretty_print = 0;
24
25 /* our jabber connection */
26 transport_client* client = NULL; 
27
28 /* the last result we received */
29 osrf_message* last_result = NULL;
30
31 /* functions */
32 int parse_request( char* request );
33 int handle_router( char* words[] );
34 int handle_time( char* words[] );
35 int handle_request( char* words[], int relay );
36 int handle_exec(char* words[]);
37 int handle_set( char* words[]);
38 int handle_print( char* words[]);
39 int send_request( char* server, 
40                 char* method, growing_buffer* buffer, int relay );
41 int parse_error( char* words[] );
42 int router_query_servers( char* server );
43 int srfsh_client_connect();
44 int print_help();
45 char* json_printer( json* object );
46 char* tabs(int count);
47 /* --------- */
48 void sig_child_handler( int s );
49
50
51
52
53 int main( int argc, char* argv[] ) {
54
55
56         if( argc < 2 ) {
57
58                 /* see if they have a .srfsh.xml in their home directory */
59                 char* home = getenv("HOME");
60                 int l = strlen(home) + 36;
61                 char fbuf[l];
62                 memset(fbuf, 0, l);
63                 sprintf(fbuf,"%s/.srfsh.xml",home);
64
65                 if(!access(fbuf, F_OK)) {
66                         if( ! osrf_system_bootstrap_client(fbuf) ) 
67                                 fatal_handler( "Unable to bootstrap client for requests");
68
69                 } else {
70                         fatal_handler( "No Config file found at %s and none specified. "
71                                         "\nusage: %s <config_file>", fbuf, argv[0] );
72                 }
73
74         } else {
75                 if( ! osrf_system_bootstrap_client(argv[1]) ) 
76                         fatal_handler( "Unable to bootstrap client for requests");
77         }
78
79         client = osrf_system_get_transport_client();
80
81
82         /* main process loop */
83         char* request;
84         while((request=readline(prompt))) {
85
86                 if( !strcmp(request, "exit") || !strcmp(request,"quit")) 
87                         break; 
88
89                 char* req_copy = strdup(request);
90
91                 parse_request( req_copy ); 
92                 add_history(request);
93
94                 free(request);
95                 free(req_copy);
96         }
97
98         free(request);
99         client_disconnect( client );
100         client_free( client );  
101         config_reader_free();   
102         log_free();
103                 
104         return 0;
105 }
106
107 void sig_child_handler( int s ) {
108         child_dead = 1;
109 }
110
111 int parse_error( char* words[] ) {
112
113         if( ! words )
114                 return 0;
115
116         int i = 0;
117         char* current;
118         char buffer[256];
119         memset(buffer, 0, 256);
120         while( (current=words[i++]) ) {
121                 strcat(buffer, current);
122                 strcat(buffer, " ");
123         }
124         if( ! buffer || strlen(buffer) < 1 ) 
125                 printf("\n");
126
127         fprintf( stderr, "Command Incomplete or Not Recognized: %s\n", buffer );
128         return 0;
129
130 }
131
132
133 int parse_request( char* request ) {
134
135         if( request == NULL )
136                 return 0;
137
138         int ret_val = 0;
139         int i = 0;
140         char* words[COMMAND_BUFSIZE]; 
141         memset(words,0,COMMAND_BUFSIZE);
142         char* req = request;
143
144         char* cur_tok = strtok( req, " " );
145
146         if( cur_tok == NULL )
147                 return 0;
148
149         while(cur_tok != NULL) {
150                 words[i++] = cur_tok;
151                 cur_tok = strtok( NULL, " " );
152         }
153
154
155         // not sure why (strtok?), but this is necessary
156         memset( words + i, 0, COMMAND_BUFSIZE - i );
157
158         /* pass off to the top level command */
159         if( !strcmp(words[0],"router") ) 
160                 ret_val = handle_router( words );
161
162         else if( !strcmp(words[0],"time") ) 
163                 ret_val = handle_time( words );
164
165         else if (!strcmp(words[0],"request"))
166                 ret_val = handle_request( words, 0 );
167
168         else if (!strcmp(words[0],"relay"))
169                 ret_val = handle_request( words, 1 );
170
171         else if (!strcmp(words[0],"help"))
172                 ret_val = print_help();
173
174         else if (!strcmp(words[0],"set"))
175                 ret_val = handle_set(words);
176
177         else if (!strcmp(words[0],"print"))
178                 ret_val = handle_print(words);
179
180         else if (words[0][0] == '!')
181                 ret_val = handle_exec( words );
182
183         if(!ret_val)
184                 return parse_error( words );
185
186         return 1;
187
188 }
189
190 int handle_set( char* words[]) {
191
192         char* variable;
193         if( (variable=words[1]) ) {
194
195                 char* val;
196                 if( (val=words[2]) ) {
197
198                         if(!strcmp(variable,"pretty_print")) {
199                                 if(!strcmp(val,"true")) {
200                                         pretty_print = 1;
201                                         printf("pretty_print = true\n");
202                                         return 1;
203                                 } 
204                                 if(!strcmp(val,"false")) {
205                                         pretty_print = 0;
206                                         printf("pretty_print = false\n");
207                                         return 1;
208                                 } 
209                         }
210                 }
211         }
212
213         return 0;
214 }
215
216
217 int handle_print( char* words[]) {
218
219         char* variable;
220         if( (variable=words[1]) ) {
221                 if(!strcmp(variable,"pretty_print")) {
222                         if(pretty_print) {
223                                 printf("pretty_print = true\n");
224                                 return 1;
225                         } else {
226                                 printf("pretty_print = false\n");
227                                 return 1;
228                         }
229                 }
230         }
231         return 0;
232 }
233
234 int handle_router( char* words[] ) {
235
236         if(!client)
237                 return 1;
238
239         int i;
240
241         if( words[1] ) { 
242                 if( !strcmp(words[1],"query") ) {
243                         
244                         if( words[2] && !strcmp(words[2],"servers") ) {
245                                 for(i=3; i < COMMAND_BUFSIZE - 3 && words[i]; i++ ) {   
246                                         router_query_servers( words[i] );
247                                 }
248                                 return 1;
249                         }
250                         return 0;
251                 }
252                 return 0;
253         }
254         return 0;
255 }
256
257
258 int handle_exec(char* words[]) {
259
260         int len = strlen(words[0]);
261         char command[len];
262         memset(command,0,len);
263
264         int i; /* chop out the ! */
265         for( i=1; i!= len; i++) {
266                 command[i-1] = words[0][i];
267         }
268
269         free(words[0]);
270         words[0] = strdup(command);
271         signal(SIGCHLD,sig_child_handler);
272         if(fork()) {
273                 while(1) {
274                         sleep(100);
275                         if(child_dead) {
276                                 signal(SIGCHLD,sig_child_handler);
277                                 child_dead = 0;
278                                 break;
279                         }
280                 }
281         } else {
282                 execvp( words[0], words );
283         }
284         return 1;
285 }
286
287
288 int handle_request( char* words[], int relay ) {
289
290         if(!client)
291                 return 1;
292
293         if(words[1]) {
294                 char* server = words[1];
295                 char* method = words[2];
296                 int i;
297                 growing_buffer* buffer = NULL;
298                 if(!relay) {
299                         buffer = buffer_init(128);
300                         buffer_add(buffer, "[");
301                         for(i = 3; words[i] != NULL; i++ ) {
302                                 buffer_add( buffer, words[i] );
303                                 buffer_add(buffer, " ");
304                         }
305                         buffer_add(buffer, "]");
306                 }
307
308                 return send_request( server, method, buffer, relay );
309         } 
310
311         return 0;
312 }
313
314 int send_request( char* server, 
315                 char* method, growing_buffer* buffer, int relay ) {
316         if( server == NULL || method == NULL )
317                 return 0;
318
319         json* params = NULL;
320         if( !relay ) {
321                 if( buffer != NULL && buffer->n_used > 0 ) 
322                         params = json_tokener_parse(buffer->buf);
323         } else {
324                 if(!last_result->result_content) { 
325                         warning_handler("We're not going to call 'relay' on empty result");
326                         return 1;
327                 }
328                 else {
329                         json* arr = json_object_new_array();
330                         json_object_array_add( arr, last_result->result_content );
331                         params = arr;
332                 }
333         }
334
335         osrf_app_session* session = osrf_app_client_session_init(server);
336         double start = get_timestamp_millis();
337
338         if(!osrf_app_session_connect(session)) {
339                 warning_handler( "Unable to connect to remote service %s\n", server );
340                 return 1;
341         }
342
343         int req_id = osrf_app_session_make_request( session, params, method, 1 );
344
345         osrf_message* omsg = osrf_app_session_request_recv( session, req_id, 8 );
346
347         if(!omsg) 
348                 printf("\nReceived no data from server\n");
349         
350         
351         while(omsg) {
352
353                 if(omsg->result_content) {
354
355                         osrf_message_free(last_result);
356                         last_result = omsg;
357
358                         if( pretty_print ) {
359                                 char* content = json_printer( omsg->result_content );
360                                 printf( "\nReceived Data: %s\n",content );
361                                 free(content);
362                         } else {
363                                 printf( "\nReceived Data: %s\n",
364                                         json_object_to_json_string(omsg->result_content));
365                         }
366
367                 } else {
368
369                         printf( "\nReceived Exception:\nName: %s\nStatus: "
370                                         "%s\nStatusCode %d\n", omsg->status_name, 
371                                         omsg->status_text, omsg->status_code );
372                 }
373
374                 omsg = osrf_app_session_request_recv( session, req_id, 5 );
375         }
376
377         double end = get_timestamp_millis();
378
379         printf("\n------------------------------------\n");
380         if( osrf_app_session_request_complete( session, req_id ))
381                 printf("Request Completed Successfully\n");
382
383
384         printf("Request Time in seconds: %f\n", end - start );
385         printf("------------------------------------\n");
386
387         osrf_app_session_request_finish( session, req_id );
388         osrf_app_session_disconnect( session );
389         osrf_app_session_destroy( session );
390
391         return 1;
392
393
394 }
395
396 int handle_time( char* words[] ) {
397
398         if( ! words[1] ) {
399
400                 char buf[36];
401                 memset(buf,0,36);
402                 get_timestamp(buf);
403                 printf( "%s\n", buf );
404                 return 1;
405         }
406
407         if( words[1] ) {
408                 time_t epoch = (time_t)atoi( words[1] );
409                 char* localtime = strdup( ctime( &epoch ) );
410                 printf( "%s => %s", words[1], localtime );
411                 free(localtime);
412                 return 1;
413         }
414
415         return 0;
416
417 }
418
419                 
420
421 int router_query_servers( char* router_server ) {
422
423         if( ! router_server || strlen(router_server) == 0 ) 
424                 return 0;
425
426         char rbuf[256];
427         memset(rbuf,0,256);
428         sprintf(rbuf,"router@%s/router", router_server );
429                 
430         transport_message* send = 
431                 message_init( "servers", NULL, NULL, rbuf, NULL );
432         message_set_router_info( send, NULL, NULL, NULL, "query", 0 );
433
434         client_send_message( client, send );
435         message_free( send );
436
437         transport_message* recv = client_recv( client, -1 );
438         if( recv == NULL ) {
439                 fprintf(stderr, "NULL message received from router\n");
440                 return 1;
441         }
442         
443         printf( 
444                         "---------------------------------------------------------------------------------\n"
445                         "Received from 'server' query on %s\n"
446                         "---------------------------------------------------------------------------------\n"
447                         "original reg time | latest reg time | last used time | class | server\n"
448                         "---------------------------------------------------------------------------------\n"
449                         "%s"
450                         "---------------------------------------------------------------------------------\n"
451                         , router_server, recv->body );
452
453         message_free( recv );
454         
455         return 1;
456 }
457                 
458 int print_help() {
459
460         printf(
461                         "---------------------------------------------------------------------------------\n"
462                         "Commands:\n"
463                         "---------------------------------------------------------------------------------\n"
464                         "help                   - Display this message\n"
465                         "!<command> [args] - Forks and runs the given command in the shell\n"
466                         "time                   - Prints the current time\n"                                    
467                         "time <timestamp>       - Formats seconds since epoch into readable format\n"   
468                         "set <variable> <value> - set a srfsh variable (e.g. set pretty_print true )\n"
469                         "print <variable>               - Displays the value of a srfsh variable\n"
470                         "---------------------------------------------------------------------------------\n"
471                         "router query servers <server1 [, server2, ...]>\n"
472                         "       - Returns stats on connected services\n"
473                         "\n"
474                         "reqeust <service> <method> [ <json formatted string of params> ]\n"
475                         "       - Anything passed in will be wrapped in a json array,\n"
476                         "               so add commas if there is more than one param\n"
477                         "\n"
478                         "relay <service> <method>\n"
479                         "       - Performs the requested query using the last received result as the param\n"
480                         "---------------------------------------------------------------------------------\n"
481                         );
482
483         return 1;
484 }
485
486
487
488 char* tabs(int count) {
489         growing_buffer* buf = buffer_init(24);
490         int i;
491         for(i=0;i!=count;i++)
492                 buffer_add(buf, "   ");
493
494         char* final = buffer_data( buf );
495         buffer_free( buf );
496         return final;
497 }
498
499 char* json_printer( json* object ) {
500
501         if(object == NULL)
502                 return NULL;
503         char* string = json_object_to_json_string(object);
504
505         growing_buffer* buf = buffer_init(64);
506         int i;
507         int tab_var = 0;
508         for(i=0; i!= strlen(string); i++) {
509
510                 if( string[i] == '{' ) {
511
512                         buffer_add(buf, "\n");
513                         char* tab = tabs(tab_var);
514                         buffer_add(buf, tab);
515                         free(tab);
516                         buffer_add( buf, "{");
517                         tab_var++;
518                         buffer_add( buf, "\n" );        
519                         tab = tabs(tab_var);
520                         buffer_add( buf, tab ); 
521                         free(tab);
522
523                 } else if( string[i] == '[' ) {
524
525                         buffer_add(buf, "\n");
526                         char* tab = tabs(tab_var);
527                         buffer_add(buf, tab);
528                         free(tab);
529                         buffer_add( buf, "[");
530                         tab_var++;
531                         buffer_add( buf, "\n" );        
532                         tab = tabs(tab_var);
533                         buffer_add( buf, tab ); 
534                         free(tab);
535
536                 } else if( string[i] == '}' ) {
537
538                         tab_var--;
539                         buffer_add(buf, "\n");
540                         char* tab = tabs(tab_var);
541                         buffer_add(buf, tab);
542                         free(tab);
543                         buffer_add( buf, "}");
544                         buffer_add( buf, "\n" );        
545                         tab = tabs(tab_var);
546                         buffer_add( buf, tab ); 
547                         free(tab);
548
549                 } else if( string[i] == ']' ) {
550
551                         tab_var--;
552                         buffer_add(buf, "\n");
553                         char* tab = tabs(tab_var);
554                         buffer_add(buf, tab);
555                         free(tab);
556                         buffer_add( buf, "]");
557                         buffer_add( buf, "\n" );        
558                         tab = tabs(tab_var);
559                         buffer_add( buf, tab ); 
560                         free(tab);
561
562                 } else {
563                         char b[2];
564                         b[0] = string[i];
565                         b[1] = '\0';
566                         buffer_add( buf, b ); 
567                 }
568
569         }
570
571         char* result = buffer_data(buf);
572         buffer_free(buf);
573         return result;
574
575 }