From 8037d8a6000423a3ae59657cded4465fdd6fc74a Mon Sep 17 00:00:00 2001 From: Trumeet Date: Tue, 26 Jul 2022 23:11:28 -0700 Subject: feat(acronc): prettify cli experience 1. Make SIGINT interrupt the current operation by forcing stdin to listen again (because the spec currently does not specify how to send the final response, so acronc will wait forever in case of invalid commands) 2. Prettify prompt and output. Signed-off-by: Trumeet --- client/acronc/client.c | 9 +++++++++ client/acronc/handler.h | 3 ++- client/acronc/handler_signal.c | 21 +++++++++++++++------ client/acronc/main.c | 37 +++++++++++++++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/client/acronc/client.c b/client/acronc/client.c index 5553d4c..3e8ca76 100644 --- a/client/acronc/client.c +++ b/client/acronc/client.c @@ -71,8 +71,10 @@ static void handle_response(const ac_response_t *response) { switch (response->type) { case AC_RESPONSE_OK: { ac_response_ok_t *o = (ac_response_ok_t *) response; +#ifdef DEBUG printf("Request %d OK.\n", o->id); +#endif break; } case AC_RESPONSE_ERROR: { @@ -85,18 +87,25 @@ static void handle_response(const ac_response_t *response) { } case AC_RESPONSE_CMD_OUT: { ac_response_cmd_out_t *o = (ac_response_cmd_out_t *) response; +#ifdef DEBUG printf("Request %d output by %s: %s.\n", o->id, o->sender, o->out); +#else + printf("%s\n", + o->out); +#endif break; } case AC_RESPONSE_CMD_RESULT: { ac_response_cmd_result_t *o = (ac_response_cmd_result_t *) response; +#ifdef DEBUG printf("Request %d is done: %s (%d).\n", o->id, o->success ? "Success" : "Failed", o->result); +#endif DEBUG break; } default: { diff --git a/client/acronc/handler.h b/client/acronc/handler.h index 1beab1c..1036f6a 100644 --- a/client/acronc/handler.h +++ b/client/acronc/handler.h @@ -10,7 +10,8 @@ extern uv_loop_t *loop; -int h_signal(void (*on_quit)(void)); +int h_signal(void (*on_int)(void), + void (*on_quit)(void)); int h_stdin(int (*on_input)(ac_request_t *req), void (*on_close)(void)); diff --git a/client/acronc/handler_signal.c b/client/acronc/handler_signal.c index d5df9d4..7dafe95 100644 --- a/client/acronc/handler_signal.c +++ b/client/acronc/handler_signal.c @@ -8,8 +8,16 @@ static uv_signal_t sigint; static uv_signal_t sigterm; -static void on_signal(uv_signal_t *handle, int signum) { - LOGDV("on_signal(handle = %p): %d", +static void on_sigint(uv_signal_t *handle, int signum) { + LOGDV("on_int(handle = %p): %d", + handle, + signum); + void (*on_int)(void) = handle->data; + on_int(); +} + +static void on_term(uv_signal_t *handle, int signum) { + LOGDV("on_term(handle = %p): %d", handle, signum); void (*on_quit)(void) = handle->data; @@ -18,14 +26,15 @@ static void on_signal(uv_signal_t *handle, int signum) { on_quit(); } -int h_signal(void (*on_quit)(void)) { +int h_signal(void (*on_int)(void), + void (*on_quit)(void)) { int r; if ((r = uv_signal_init(loop, &sigint))) return r; - sigint.data = on_quit; - if ((r = uv_signal_start(&sigint, on_signal, SIGINT))) return r; + sigint.data = on_int; + if ((r = uv_signal_start(&sigint, on_sigint, SIGINT))) return r; if ((r = uv_signal_init(loop, &sigterm))) return r; sigterm.data = on_quit; - if ((r = uv_signal_start(&sigterm, on_signal, SIGTERM))) return r; + if ((r = uv_signal_start(&sigterm, on_term, SIGTERM))) return r; return 0; } diff --git a/client/acronc/main.c b/client/acronc/main.c index d0e67ef..3f68553 100644 --- a/client/acronc/main.c +++ b/client/acronc/main.c @@ -14,10 +14,12 @@ #include #include #include +#include static uv_loop_t lop; uv_loop_t *loop = &lop; static int current_req = -1; +static bool tty = true; static void on_close(uv_handle_t *handle); @@ -47,7 +49,17 @@ static void on_sock_closed(void) { uv_stop(loop); } +static void prompt(void) { + if (tty) { + fprintf(stderr, "> "); + } +} + static int on_input(ac_request_t *req) { + if (req->type == AC_REQUEST_CMD && ((ac_request_cmd_t *) req)->cmd[0] == '\0') { + prompt(); + return 0; + } current_req = req->id; stdin_stop(); LOGD("Stdin is paused."); @@ -56,10 +68,12 @@ static int on_input(ac_request_t *req) { } static int on_sock_ready(void) { + prompt(); return h_stdin(on_input, on_stdin_closed); } static int on_recv(ac_obj_t *obj) { + bool p = false; if (AC_IS_RESPONSE(obj->type)) { ac_response_t *resp = (ac_response_t *) obj; if (resp->id == current_req) { @@ -70,11 +84,16 @@ static int on_recv(ac_obj_t *obj) { LOGEV("Cannot resume stdin: %s", uv_strerror(r)); } else { LOGD("Stdin is resumed."); + p = true; } } } } - return handle_object(obj); + const int retval = handle_object(obj); + if (p) { + prompt(); + } + return retval; } static void on_resolv(int status, const struct addrinfo *ai, void (*on_connected)(bool)) { @@ -95,11 +114,25 @@ static void on_resolv(int status, const struct addrinfo *ai, void (*on_connected } } +static void on_int(void) { + current_req = -1; + int r = stdin_start(); + if (r && r != UV_EALREADY) { + LOGEV("Cannot resume stdin: %s", uv_strerror(r)); + } else { + printf("Interrupt\n"); + prompt(); + } +} + int main(int argc, const char **argv) { int r; if ((r = config_parse(argc, argv, ¶ms))) return r; atexit(cleanup); + if (!isatty(fileno(stdin))) { + tty = false; + } libac_config_t config = { #ifdef DEBUG .out = NULL, @@ -111,7 +144,7 @@ int main(int argc, const char **argv) { if ((r = ac_init(&config))) errx(r, "Cannot initialize Acron library."); if ((r = uv_loop_init(loop))) goto uviniterr; - if ((r = h_signal(on_stdin_closed))) goto uviniterr; + if ((r = h_signal(on_int, on_stdin_closed))) goto uviniterr; if ((r = a_dns(params.host, params.port, on_resolv))) goto uviniterr; if ((r = uv_run(loop, UV_RUN_DEFAULT))) { -- cgit v1.2.3