From 623d96fe9a47679960d7f1a4f92c563479bb5613 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 3 Apr 2019 09:21:47 -0400 Subject: [PATCH 01/17] Use shared_ptr to WS connection in API connection --- include/fc/rpc/websocket_api.hpp | 7 +++-- src/rpc/websocket_api.cpp | 54 +++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/include/fc/rpc/websocket_api.hpp b/include/fc/rpc/websocket_api.hpp index ebb6fe74a..8f06a19fb 100644 --- a/include/fc/rpc/websocket_api.hpp +++ b/include/fc/rpc/websocket_api.hpp @@ -10,7 +10,8 @@ namespace fc { namespace rpc { class websocket_api_connection : public api_connection { public: - websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_conversion_depth ); + websocket_api_connection( const std::shared_ptr &c, + uint32_t max_conversion_depth ); ~websocket_api_connection(); virtual variant send_call( @@ -29,8 +30,8 @@ namespace fc { namespace rpc { const std::string& message, bool send_message = true ); - fc::http::websocket_connection& _connection; - fc::rpc::state _rpc_state; + std::shared_ptr _connection; + fc::rpc::state _rpc_state; }; } } // namespace fc::rpc diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index ae4e26e1d..7df32dc15 100644 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -7,9 +7,11 @@ websocket_api_connection::~websocket_api_connection() { } -websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_depth ) +websocket_api_connection::websocket_api_connection( const std::shared_ptr& c, + uint32_t max_depth ) : api_connection(max_depth),_connection(c) { + FC_ASSERT( c ); _rpc_state.add_method( "call", [this]( const variants& args ) -> variant { FC_ASSERT( args.size() == 3 && args[2].is_array() ); @@ -47,9 +49,9 @@ websocket_api_connection::websocket_api_connection( fc::http::websocket_connecti return this->receive_call( 0, method_name, args ); } ); - _connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg,true); } ); - _connection.on_http_handler( [&]( const std::string& msg ){ return on_message(msg,false); } ); - _connection.closed.connect( [this](){ closed(); } ); + _connection->on_message_handler( [this]( const std::string& msg ){ on_message(msg,true); } ); + _connection->on_http_handler( [this]( const std::string& msg ){ return on_message(msg,false); } ); + _connection->closed.connect( [this](){ closed(); } ); } variant websocket_api_connection::send_call( @@ -57,29 +59,43 @@ variant websocket_api_connection::send_call( string method_name, variants args /* = variants() */ ) { - auto request = _rpc_state.start_remote_call( "call", {api_id, std::move(method_name), std::move(args) } ); - _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), - fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); - return _rpc_state.wait_for_response( *request.id ); + if( _connection ) + { + auto request = _rpc_state.start_remote_call( "call", { api_id, std::move(method_name), std::move(args) } ); + _connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ) ); + return _rpc_state.wait_for_response( *request.id ); + } + return variant(); // TODO return an error } variant websocket_api_connection::send_callback( uint64_t callback_id, variants args /* = variants() */ ) { - auto request = _rpc_state.start_remote_call( "callback", {callback_id, std::move(args) } ); - _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), - fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); - return _rpc_state.wait_for_response( *request.id ); + if( _connection ) + { + auto request = _rpc_state.start_remote_call( "callback", { callback_id, std::move(args) } ); + _connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ) ); + return _rpc_state.wait_for_response( *request.id ); + } + return variant(); // TODO return an error } void websocket_api_connection::send_notice( uint64_t callback_id, variants args /* = variants() */ ) { - fc::rpc::request req{ optional(), "notice", {callback_id, std::move(args)}}; - _connection.send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth), - fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); + if( _connection ) + { + fc::rpc::request req{ optional(), "notice", { callback_id, std::move(args) } }; + _connection->send_message( fc::json::to_string( fc::variant( req, _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ) ); + } } std::string websocket_api_connection::on_message( @@ -117,8 +133,8 @@ std::string websocket_api_connection::on_message( if( call.id ) { auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); - if( send_message ) - _connection.send_message( reply ); + if( send_message && _connection ) + _connection->send_message( reply ); return reply; } } @@ -135,8 +151,8 @@ std::string websocket_api_connection::on_message( auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); - if( send_message ) - _connection.send_message( reply ); + if( send_message && _connection ) + _connection->send_message( reply ); return reply; } From 15d751c3d0f711ed4b16a7620eb8976175f6ddc0 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 3 Apr 2019 09:32:31 -0400 Subject: [PATCH 02/17] Wrap long lines --- src/rpc/websocket_api.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index 7df32dc15..89020046d 100644 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -125,14 +125,18 @@ std::string websocket_api_connection::on_message( auto end = time_point::now(); if( end - start > fc::milliseconds( LOG_LONG_API_MAX_MS ) ) - elog( "API call execution time limit exceeded. method: ${m} params: ${p} time: ${t}", ("m",call.method)("p",call.params)("t", end - start) ); + elog( "API call execution time limit exceeded. method: ${m} params: ${p} time: ${t}", + ("m",call.method)("p",call.params)("t", end - start) ); else if( end - start > fc::milliseconds( LOG_LONG_API_WARN_MS ) ) - wlog( "API call execution time nearing limit. method: ${m} params: ${p} time: ${t}", ("m",call.method)("p",call.params)("t", end - start) ); + wlog( "API call execution time nearing limit. method: ${m} params: ${p} time: ${t}", + ("m",call.method)("p",call.params)("t", end - start) ); #endif if( call.id ) { - auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); + auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ); if( send_message && _connection ) _connection->send_message( reply ); return reply; From 03cc93d0e4df1909aa72dffc324423dd6c747a51 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 3 Apr 2019 09:37:38 -0400 Subject: [PATCH 03/17] Update WS API test cases due to param type change --- tests/api.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api.cpp b/tests/api.cpp index e0514c389..fbe42f2e0 100644 --- a/tests/api.cpp +++ b/tests/api.cpp @@ -61,7 +61,7 @@ int main( int argc, char** argv ) fc::http::websocket_server server; server.on_connection([&]( const websocket_connection_ptr& c ){ - auto wsc = std::make_shared(*c, MAX_DEPTH); + auto wsc = std::make_shared(c, MAX_DEPTH); auto login = std::make_shared(); login->calc = calc_api; wsc->register_api(fc::api(login)); @@ -76,7 +76,7 @@ int main( int argc, char** argv ) try { fc::http::websocket_client client; auto con = client.connect( "ws://localhost:8090" ); - auto apic = std::make_shared(*con, MAX_DEPTH); + auto apic = std::make_shared(con, MAX_DEPTH); auto remote_login_api = apic->get_remote_api(); auto remote_calc = remote_login_api->get_calc(); remote_calc->on_result( []( uint32_t r ) { elog( "callback result ${r}", ("r",r) ); } ); From 3655fe148b438ae0a7515b5e37f5c64135aa8361 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 3 Apr 2019 12:05:40 -0400 Subject: [PATCH 04/17] Minor code refactory --- src/rpc/websocket_api.cpp | 50 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index 89020046d..d1dd99704 100644 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -11,7 +11,7 @@ websocket_api_connection::websocket_api_connection( const std::shared_ptr variant { FC_ASSERT( args.size() == 3 && args[2].is_array() ); @@ -59,43 +59,41 @@ variant websocket_api_connection::send_call( string method_name, variants args /* = variants() */ ) { - if( _connection ) - { - auto request = _rpc_state.start_remote_call( "call", { api_id, std::move(method_name), std::move(args) } ); - _connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ), - fc::json::stringify_large_ints_and_doubles, - _max_conversion_depth ) ); - return _rpc_state.wait_for_response( *request.id ); - } - return variant(); // TODO return an error + if( !_connection ) // defensive check + return variant(); // TODO return an error? + + auto request = _rpc_state.start_remote_call( "call", { api_id, std::move(method_name), std::move(args) } ); + _connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ) ); + return _rpc_state.wait_for_response( *request.id ); } variant websocket_api_connection::send_callback( uint64_t callback_id, variants args /* = variants() */ ) { - if( _connection ) - { - auto request = _rpc_state.start_remote_call( "callback", { callback_id, std::move(args) } ); - _connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ), - fc::json::stringify_large_ints_and_doubles, - _max_conversion_depth ) ); - return _rpc_state.wait_for_response( *request.id ); - } - return variant(); // TODO return an error + if( !_connection ) // defensive check + return variant(); // TODO return an error? + + auto request = _rpc_state.start_remote_call( "callback", { callback_id, std::move(args) } ); + _connection->send_message( fc::json::to_string( fc::variant( request, _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ) ); + return _rpc_state.wait_for_response( *request.id ); } void websocket_api_connection::send_notice( uint64_t callback_id, variants args /* = variants() */ ) { - if( _connection ) - { - fc::rpc::request req{ optional(), "notice", { callback_id, std::move(args) } }; - _connection->send_message( fc::json::to_string( fc::variant( req, _max_conversion_depth ), - fc::json::stringify_large_ints_and_doubles, - _max_conversion_depth ) ); - } + if( !_connection ) // defensive check + return; + + fc::rpc::request req{ optional(), "notice", { callback_id, std::move(args) } }; + _connection->send_message( fc::json::to_string( fc::variant( req, _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, + _max_conversion_depth ) ); } std::string websocket_api_connection::on_message( From a71893adbaa5c12954ff31a6353f3e61097ae466 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 2 May 2019 21:42:17 -0400 Subject: [PATCH 05/17] Improve CLI tab completion feature For example, if there are 3 commands: "gethelp", "get_account" and "get_account_name", input "ge" then press TAB, the command will be completed to "get"; press TAB again, a list with all 3 commands will show; input "get_ac" then press TAB, the command will be completed to "get_account"; press TAB again, a list with "get_account" and "get_account_name" will show. --- src/rpc/cli.cpp | 54 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index d106253c3..ed0ae3086 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -137,36 +137,52 @@ void cli::run() */ static char *my_rl_complete(char *token, int *match) { - bool have_one = false; - std::string method_name; - - auto& cmd = cli_commands(); + const auto& cmds = cli_commands(); const size_t partlen = strlen (token); /* Part of token */ - for (const std::string& it : cmd) + std::vector> matched_cmds; + for( const std::string& it : cmds ) { - if (it.compare(0, partlen, token) == 0) + if( it.compare(0, partlen, token) == 0 ) { - if (have_one) { - // we can only have 1, but we found a second - return NULL; - } - else - { - method_name = it; - have_one = true; - } + matched_cmds.push_back( it ); } } - if (have_one) + if( matched_cmds.size() == 0 ) + return NULL; + + const std::string& first_matched_cmd = matched_cmds[0]; + if( matched_cmds.size() == 1 ) { *match = 1; - method_name += " "; - return strdup (method_name.c_str() + partlen); + std::string matched_cmd = first_matched_cmd + " "; + return strdup( matched_cmd.c_str() + partlen ); } - return NULL; + size_t first_cmd_len = first_matched_cmd.size(); + size_t matched_len = partlen; + for( ; matched_len < first_cmd_len; ++matched_len ) + { + char next_char = first_matched_cmd[matched_len]; + bool end = false; + for( const std::string& s : matched_cmds ) + { + if( s.size() <= matched_len || s[matched_len] != next_char ) + { + end = true; + break; + } + } + if( end ) + break; + } + + if( matched_len == partlen ) + return NULL; + + std::string matched_cmd_part = first_matched_cmd.substr( partlen, matched_len - partlen ); + return strdup( matched_cmd_part.c_str() ); } /*** From bd3036df8aebbdad882b1ec8fd12c832133efdec Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 3 May 2019 09:46:13 -0400 Subject: [PATCH 06/17] Increase CLI command history buffer size to 256 --- src/rpc/cli.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index ed0ae3086..5e25f9792 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -56,6 +56,11 @@ void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ ) void cli::start() { cli_commands() = get_method_names(0); + +#ifdef HAVE_EDITLINE +el_hist_size = 256; +#endif + _run_complete = fc::async( [&](){ run(); } ); } From 635cbc24e7483ec4445389e770fb568022a2d091 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 7 May 2019 17:33:34 -0400 Subject: [PATCH 07/17] Return the signal_set when setting signal handler --- include/fc/interprocess/signals.hpp | 7 +++++-- src/interprocess/signals.cpp | 23 ++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/fc/interprocess/signals.hpp b/include/fc/interprocess/signals.hpp index 876c68497..dd791d11d 100644 --- a/include/fc/interprocess/signals.hpp +++ b/include/fc/interprocess/signals.hpp @@ -1,8 +1,11 @@ #pragma once #include +#include namespace fc { - /// handler will be called from ASIO thread - void set_signal_handler( std::function handler, int signal_num ); + /// Set a handler to process an IPC (inter process communication) signal. + /// Handler will be called from ASIO thread. + /// @return shared pointer to the signal_set that holds the handler + std::shared_ptr set_signal_handler( std::function handler, int signal_num ); } diff --git a/src/interprocess/signals.cpp b/src/interprocess/signals.cpp index f65f1228f..2a4652c81 100644 --- a/src/interprocess/signals.cpp +++ b/src/interprocess/signals.cpp @@ -3,15 +3,16 @@ namespace fc { - void set_signal_handler( std::function handler, int signal_num ) - { - std::shared_ptr sig_set(new boost::asio::signal_set(fc::asio::default_io_service(), signal_num)); - sig_set->async_wait( - [sig_set,handler]( const boost::system::error_code& err, int num ) - { - handler( num ); - sig_set->cancel(); - // set_signal_handler( handler, signal_num ); - } ); - } + std::shared_ptr set_signal_handler( std::function handler, int signal_num ) + { + std::shared_ptr sig_set( new boost::asio::signal_set( fc::asio::default_io_service(), + signal_num) ); + sig_set->async_wait( [sig_set,handler]( const boost::system::error_code& err, int num ) + { + if( err != boost::asio::error::operation_aborted ) + handler( num ); + sig_set->cancel(); + } ); + return sig_set; + } } From 127aadbffc1950e4cbb8ea73ef96a211d6560d26 Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 7 May 2019 17:39:38 -0400 Subject: [PATCH 08/17] Add function to send signals to threads --- include/fc/thread/thread.hpp | 5 +++++ src/thread/thread.cpp | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/fc/thread/thread.hpp b/include/fc/thread/thread.hpp index 282fc3049..59545fe77 100644 --- a/include/fc/thread/thread.hpp +++ b/include/fc/thread/thread.hpp @@ -131,6 +131,11 @@ namespace fc { * @todo make quit non-blocking of the calling thread by eliminating the call to boost::thread::join */ void quit(); + + /** + * Send signal to underlying native thread. Only for Linux and macOS + */ + void signal(int); /** * @return true unless quit() has been called. diff --git a/src/thread/thread.cpp b/src/thread/thread.cpp index f1c1e99af..ef456325f 100644 --- a/src/thread/thread.cpp +++ b/src/thread/thread.cpp @@ -156,6 +156,17 @@ namespace fc { void thread::debug( const fc::string& d ) { /*my->debug(d);*/ } +#if defined(__linux__) || defined(__APPLE__) +#include +#endif + + void thread::signal(int sig) + { +#if defined(__linux__) || defined(__APPLE__) + pthread_kill( my->boost_thread->native_handle(), sig ); +#endif + } + void thread::quit() { //if quitting from a different thread, start quit task on thread. From ed3f1c86dde16abaf284a1299f07d73e2d43e30b Mon Sep 17 00:00:00 2001 From: abitmore Date: Tue, 7 May 2019 19:20:46 -0400 Subject: [PATCH 09/17] Fix signal handling in CLI --- include/fc/rpc/cli.hpp | 2 + src/rpc/cli.cpp | 103 ++++++++++++++++++++++++++++++----------- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/include/fc/rpc/cli.hpp b/include/fc/rpc/cli.hpp index 00714a849..3ac3a1067 100644 --- a/include/fc/rpc/cli.hpp +++ b/include/fc/rpc/cli.hpp @@ -25,6 +25,7 @@ namespace fc { namespace rpc { void start(); void stop(); + void cancel(); void wait(); void format_result( const string& method, std::function formatter); @@ -40,5 +41,6 @@ namespace fc { namespace rpc { std::string _prompt = ">>>"; std::map > _result_formatters; fc::future _run_complete; + fc::thread* _getline_thread = nullptr; ///< Wait for user input in this thread }; } } diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index 5e25f9792..fe2e462d3 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -9,6 +9,7 @@ #ifdef HAVE_EDITLINE # include "editline.h" +# include # ifdef WIN32 # include # endif @@ -53,21 +54,22 @@ void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ ) FC_ASSERT(false); } -void cli::start() +void cli::stop() { - cli_commands() = get_method_names(0); - -#ifdef HAVE_EDITLINE -el_hist_size = 256; -#endif - - _run_complete = fc::async( [&](){ run(); } ); + cancel(); + _run_complete.wait(); } -void cli::stop() +void cli::cancel() { _run_complete.cancel(); - _run_complete.wait(); +#ifdef HAVE_EDITLINE + if( _getline_thread ) + { + _getline_thread->signal(SIGINT); + _getline_thread = nullptr; + } +#endif } void cli::wait() @@ -103,6 +105,20 @@ void cli::run() } catch ( const fc::eof_exception& e ) { + if( _getline_thread ) + { + _getline_thread->quit(); + _getline_thread = nullptr; + } + break; + } + catch ( const fc::canceled_exception& e ) + { + if( _getline_thread ) + { + _getline_thread->quit(); + _getline_thread = nullptr; + } break; } @@ -128,6 +144,11 @@ void cli::run() if (e.code() == fc::canceled_exception_code) { + if( _getline_thread ) + { + _getline_thread->quit(); + _getline_thread = nullptr; + } break; } } @@ -237,6 +258,39 @@ static int cli_check_secret(const char *source) return 0; } +/** + * Get next character from stdin, or EOF if got a SIGINT signal + */ +static int interruptable_getc(void) +{ + int r; + char c; + + r = read(0, &c, 1); // read from stdin, will return -1 on SIGINT + + return r == 1 ? c : EOF; +} + +void cli::start() +{ + +#ifdef HAVE_EDITLINE + el_hist_size = 256; + + rl_set_complete_func(my_rl_complete); + rl_set_list_possib_func(cli_completion); + rl_set_check_secret_func(cli_check_secret); + rl_set_getc_func(interruptable_getc); + + static fc::thread getline_thread("getline"); + _getline_thread = &getline_thread; + + cli_commands() = get_method_names(0); +#endif + + _run_complete = fc::async( [&](){ run(); } ); +} + /*** * @brief Read input from the user * @param prompt the prompt to display @@ -258,21 +312,19 @@ void cli::getline( const fc::string& prompt, fc::string& line) if( _isatty( _fileno( stdin ) ) ) #endif { - rl_set_complete_func(my_rl_complete); - rl_set_list_possib_func(cli_completion); - rl_set_check_secret_func(cli_check_secret); - - static fc::thread getline_thread("getline"); - getline_thread.async( [&](){ - char* line_read = nullptr; - std::cout.flush(); //readline doesn't use cin, so we must manually flush _out - line_read = readline(prompt.c_str()); - if( line_read == nullptr ) - FC_THROW_EXCEPTION( fc::eof_exception, "" ); - line = line_read; - // we don't need here to add line in editline's history, cause it will be doubled - free(line_read); - }).wait(); + if( _getline_thread ) + { + _getline_thread->async( [&prompt,&line](){ + char* line_read = nullptr; + std::cout.flush(); //readline doesn't use cin, so we must manually flush _out + line_read = readline(prompt.c_str()); + if( line_read == nullptr ) + FC_THROW_EXCEPTION( fc::eof_exception, "" ); + line = line_read; + // we don't need here to add line in editline's history, cause it will be doubled + free(line_read); + }).wait(); + } } else #endif @@ -280,7 +332,6 @@ void cli::getline( const fc::string& prompt, fc::string& line) std::cout << prompt; // sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline"); fc::getline( fc::cin, line ); - return; } } From 382970bfa4d60ffd027c64b9ad37d1c545e9b977 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 8 May 2019 03:51:40 -0400 Subject: [PATCH 10/17] Suppress error message when CLI is quitting --- src/rpc/cli.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index fe2e462d3..414f39953 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -140,8 +140,6 @@ void cli::run() } catch ( const fc::exception& e ) { - std::cout << e.to_detail_string() << "\n"; - if (e.code() == fc::canceled_exception_code) { if( _getline_thread ) @@ -151,6 +149,7 @@ void cli::run() } break; } + std::cout << e.to_detail_string() << "\n"; } } } From c5c94c45f88e292fd5ae6b12a7c2f0311742095b Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 8 May 2019 05:00:57 -0400 Subject: [PATCH 11/17] Bump editline submodule --- vendor/editline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/editline b/vendor/editline index fbb1f8800..0eb8f228f 160000 --- a/vendor/editline +++ b/vendor/editline @@ -1 +1 @@ -Subproject commit fbb1f8800adbb70264fa3893dc221f524e25708c +Subproject commit 0eb8f228f74253bd6312d8ed61c529c43452cc83 From bac31e38223141f8d26895ab8c1a1c943b2799f8 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 8 May 2019 05:08:41 -0400 Subject: [PATCH 12/17] Temporarily comment out check_secret in CLI due to editline bump --- src/rpc/cli.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index 414f39953..2829066c1 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -278,7 +278,7 @@ void cli::start() rl_set_complete_func(my_rl_complete); rl_set_list_possib_func(cli_completion); - rl_set_check_secret_func(cli_check_secret); + //rl_set_check_secret_func(cli_check_secret); rl_set_getc_func(interruptable_getc); static fc::thread getline_thread("getline"); From 51747090a836611ac2067f2174f566fc8b650a22 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 8 May 2019 05:23:02 -0400 Subject: [PATCH 13/17] Minor function name change --- src/rpc/cli.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index 2829066c1..ac518c372 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -260,7 +260,7 @@ static int cli_check_secret(const char *source) /** * Get next character from stdin, or EOF if got a SIGINT signal */ -static int interruptable_getc(void) +static int interruptible_getc(void) { int r; char c; @@ -279,7 +279,7 @@ void cli::start() rl_set_complete_func(my_rl_complete); rl_set_list_possib_func(cli_completion); //rl_set_check_secret_func(cli_check_secret); - rl_set_getc_func(interruptable_getc); + rl_set_getc_func(interruptible_getc); static fc::thread getline_thread("getline"); _getline_thread = &getline_thread; From 301f58200202f5a7d17617e293ed2da5e350c9da Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 8 May 2019 06:46:36 -0400 Subject: [PATCH 14/17] Handle SIGINT when searching in editline --- src/rpc/cli.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index ac518c372..c4e44ce7c 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -257,16 +257,24 @@ static int cli_check_secret(const char *source) return 0; } +static int cli_quitting = false; + /** * Get next character from stdin, or EOF if got a SIGINT signal */ static int interruptible_getc(void) { + if( cli_quitting ) + return EOF; + int r; char c; r = read(0, &c, 1); // read from stdin, will return -1 on SIGINT + if( r == -1 && errno == EINTR ) + cli_quitting = true; + return r == 1 ? c : EOF; } From 9605f4826bb55e1df1d3cffb6a6896c1541d73a9 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 May 2019 13:22:24 -0400 Subject: [PATCH 15/17] Bump editline submodule --- vendor/editline | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/editline b/vendor/editline index 0eb8f228f..13f8d5f69 160000 --- a/vendor/editline +++ b/vendor/editline @@ -1 +1 @@ -Subproject commit 0eb8f228f74253bd6312d8ed61c529c43452cc83 +Subproject commit 13f8d5f69c3a048e0b6bdb979d617940eed32ef0 From b562d81a65da6566b7707d1bae127bc52bc083f7 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 May 2019 13:50:53 -0400 Subject: [PATCH 16/17] Let CLI be able to restart --- src/rpc/cli.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index c4e44ce7c..c6095d617 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -105,20 +105,12 @@ void cli::run() } catch ( const fc::eof_exception& e ) { - if( _getline_thread ) - { - _getline_thread->quit(); - _getline_thread = nullptr; - } + _getline_thread = nullptr; break; } catch ( const fc::canceled_exception& e ) { - if( _getline_thread ) - { - _getline_thread->quit(); - _getline_thread = nullptr; - } + _getline_thread = nullptr; break; } @@ -142,11 +134,7 @@ void cli::run() { if (e.code() == fc::canceled_exception_code) { - if( _getline_thread ) - { - _getline_thread->quit(); - _getline_thread = nullptr; - } + _getline_thread = nullptr; break; } std::cout << e.to_detail_string() << "\n"; @@ -257,6 +245,10 @@ static int cli_check_secret(const char *source) return 0; } +/*** + * Indicates whether CLI is quitting after got a SIGINT signal. + * In order to be used by editline which is C-style, this is a global variable. + */ static int cli_quitting = false; /** @@ -292,6 +284,8 @@ void cli::start() static fc::thread getline_thread("getline"); _getline_thread = &getline_thread; + cli_quitting = false; + cli_commands() = get_method_names(0); #endif From 3d39a51cdcea2dc2424d5e75e22900a9e760e010 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 9 May 2019 13:57:03 -0400 Subject: [PATCH 17/17] Capture only `this` in cli::start() --- src/rpc/cli.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index c6095d617..ba7f6e528 100644 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -289,7 +289,7 @@ void cli::start() cli_commands() = get_method_names(0); #endif - _run_complete = fc::async( [&](){ run(); } ); + _run_complete = fc::async( [this](){ run(); } ); } /***