diff --git a/include/fc/rpc/cli.hpp b/include/fc/rpc/cli.hpp index 5669745..6670a14 100755 --- a/include/fc/rpc/cli.hpp +++ b/include/fc/rpc/cli.hpp @@ -25,22 +25,18 @@ namespace fc { namespace rpc { void start(); void stop(); - void cancel(); void wait(); void format_result( const string& method, std::function formatter); - virtual void getline( const std::string& prompt, std::string& line ); + virtual void getline( const fc::string& prompt, fc::string& line ); void set_prompt( const string& prompt ); - void set_regex_secret( const string& expr ); - private: void run(); std::string _prompt = ">>>"; std::map > _result_formatters; fc::future _run_complete; - fc::thread* _getline_thread = nullptr; ///< Wait for user input in this thread }; -} } \ No newline at end of file +} } diff --git a/include/fc/thread/thread.hpp b/include/fc/thread/thread.hpp index a2bc144..bb82710 100755 --- a/include/fc/thread/thread.hpp +++ b/include/fc/thread/thread.hpp @@ -112,11 +112,6 @@ namespace fc { */ 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/rpc/cli.cpp b/src/rpc/cli.cpp index 636101a..89cdc8a 100755 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -9,22 +9,13 @@ #ifdef HAVE_EDITLINE # include "editline.h" -# include # ifdef WIN32 # include # endif #endif -#include - namespace fc { namespace rpc { -static boost::regex& cli_regex_secret() -{ - static boost::regex regex_expr; - return regex_expr; -} - static std::vector& cli_commands() { static std::vector* cmds = new std::vector(); @@ -54,6 +45,23 @@ void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ ) FC_ASSERT(false); } +void cli::start() +{ + cli_commands() = get_method_names(0); + _run_complete = fc::async( [&](){ run(); } ); +} + +void cli::stop() +{ + _run_complete.cancel(); + _run_complete.wait(); +} + +void cli::wait() +{ + _run_complete.wait(); +} + void cli::format_result( const string& method, std::function formatter) { _result_formatters[method] = formatter; @@ -64,11 +72,6 @@ void cli::set_prompt( const string& prompt ) _prompt = prompt; } -void cli::set_regex_secret( const string& expr ) -{ - cli_regex_secret() = expr; -} - void cli::run() { while( !_run_complete.canceled() ) @@ -82,17 +85,11 @@ void cli::run() } catch ( const fc::eof_exception& e ) { - _getline_thread = nullptr; break; } - catch ( const fc::canceled_exception& e ) - { - _getline_thread = nullptr; - break; - } - + std::cout << line << "\n"; line += char(EOF); - fc::variants args = fc::json::variants_from_string(line); + fc::variants args = fc::json::variants_from_string(line);; if( args.size() == 0 ) continue; @@ -109,16 +106,17 @@ void cli::run() } catch ( const fc::exception& e ) { + std::cout << e.to_detail_string() << "\n"; + if (e.code() == fc::canceled_exception_code) { - _getline_thread = nullptr; break; } - std::cout << e.to_detail_string() << "\n"; } } } + /**** * @brief loop through list of commands, attempting to find a match * @param token what the user typed @@ -127,52 +125,36 @@ void cli::run() */ static char *my_rl_complete(char *token, int *match) { - const auto& cmds = cli_commands(); - const size_t partlen = strlen (token); /* Part of token */ + bool have_one = false; + std::string method_name; - std::vector> matched_cmds; - for( const std::string& it : cmds ) + auto& cmd = cli_commands(); + int partlen = strlen (token); /* Part of token */ + + for (const std::string& it : cmd) { - if( it.compare(0, partlen, token) == 0 ) + if (it.compare(0, partlen, token) == 0) { - matched_cmds.push_back( it ); - } - } - - if( matched_cmds.size() == 0 ) - return NULL; - - const std::string& first_matched_cmd = matched_cmds[0]; - if( matched_cmds.size() == 1 ) - { - *match = 1; - std::string matched_cmd = first_matched_cmd + " "; - return strdup( matched_cmd.c_str() + partlen ); - } - - 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 ) + if (have_one) { + // we can only have 1, but we found a second + return NULL; + } + else { - end = true; - break; + method_name = it; + have_one = true; } } - if( end ) - break; } - if( matched_len == partlen ) - return NULL; + if (have_one) + { + *match = 1; + method_name += " "; + return strdup (method_name.c_str() + partlen); + } - std::string matched_cmd_part = first_matched_cmd.substr( partlen, matched_len - partlen ); - return strdup( matched_cmd_part.c_str() ); + return NULL; } /*** @@ -194,7 +176,7 @@ static int cli_completion(char *token, char ***array) } int total_matches = 0; - const size_t partlen = strlen(token); + int partlen = strlen(token); for (const std::string& it : cmd) { @@ -209,98 +191,12 @@ static int cli_completion(char *token, char ***array) return total_matches; } -/*** - * @brief regex match for secret information - * @param source the incoming text source - * @returns integer 1 in event of regex match for secret information, otherwise 0 - */ -static int cli_check_secret(const char *source) -{ - if (!cli_regex_secret().empty() && boost::regex_match(source, cli_regex_secret())) - return 1; - - 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; - -#ifndef WIN32 -/** - * 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 && !cli_quitting ? c : EOF; -} -#endif - -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(interruptible_getc); - - static fc::thread getline_thread("getline"); - _getline_thread = &getline_thread; - - cli_quitting = false; - - cli_commands() = get_method_names(0); -#endif - - _run_complete = fc::async( [this](){ run(); } ); -} - -void cli::cancel() -{ - _run_complete.cancel(); -#ifdef HAVE_EDITLINE - cli_quitting = true; - if( _getline_thread ) - { - _getline_thread->signal(SIGINT); - _getline_thread = nullptr; - } -#endif -} - -void cli::stop() -{ - cancel(); - _run_complete.wait(); -} - -void cli::wait() -{ - _run_complete.wait(); -} - /*** * @brief Read input from the user * @param prompt the prompt to display * @param line what the user typed */ -void cli::getline( const std::string& prompt, std::string& line) +void cli::getline( const fc::string& prompt, fc::string& line) { // getting file descriptor for C++ streams is near impossible // so we just assume it's the same as the C stream... @@ -316,28 +212,29 @@ void cli::getline( const std::string& prompt, std::string& line) if( _isatty( _fileno( stdin ) ) ) #endif { - 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 - if (cli_check_secret(line_read)) { - free(line_read); - el_no_echo = 1; - line_read = readline("Enter password: "); - el_no_echo = 0; - if( line_read == nullptr ) - FC_THROW_EXCEPTION( fc::eof_exception, "" ); - line = line + ' ' + line_read; - } + rl_set_complete_func(my_rl_complete); + rl_set_list_possib_func(cli_completion); +jjkkljk; + 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; + try + { + if (*line_read) + add_history(line_read); + } + catch(...) + { free(line_read); - }).wait(); - } + throw; + } + free(line_read); + }).wait(); } else #endif @@ -345,7 +242,8 @@ void cli::getline( const std::string& prompt, std::string& line) std::cout << prompt; // sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline"); fc::getline( fc::cin, line ); + return; } } -} } // namespace fc::rpc \ No newline at end of file +} } // namespace fc::rpc diff --git a/src/thread/thread.cpp b/src/thread/thread.cpp index a1261d3..25ba77c 100755 --- a/src/thread/thread.cpp +++ b/src/thread/thread.cpp @@ -147,16 +147,7 @@ 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.