Revert "updated to editline changes, brought all updates"

This reverts commit 8fe703c35a.
This commit is contained in:
pravin-battu 2020-10-15 09:54:05 -03:00
parent 252e3df0c4
commit b7d4e4e37b
4 changed files with 71 additions and 191 deletions

View file

@ -25,22 +25,18 @@ namespace fc { namespace rpc {
void start(); void start();
void stop(); void stop();
void cancel();
void wait(); void wait();
void format_result( const string& method, std::function<string(variant,const variants&)> formatter); void format_result( const string& method, std::function<string(variant,const variants&)> 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_prompt( const string& prompt );
void set_regex_secret( const string& expr );
private: private:
void run(); void run();
std::string _prompt = ">>>"; std::string _prompt = ">>>";
std::map<string,std::function<string(variant,const variants&)> > _result_formatters; std::map<string,std::function<string(variant,const variants&)> > _result_formatters;
fc::future<void> _run_complete; fc::future<void> _run_complete;
fc::thread* _getline_thread = nullptr; ///< Wait for user input in this thread
}; };
} } } }

View file

@ -112,11 +112,6 @@ namespace fc {
*/ */
void quit(); void quit();
/**
* Send signal to underlying native thread. Only for Linux and macOS
*/
void signal(int);
/** /**
* @return true unless quit() has been called. * @return true unless quit() has been called.
*/ */

View file

@ -9,22 +9,13 @@
#ifdef HAVE_EDITLINE #ifdef HAVE_EDITLINE
# include "editline.h" # include "editline.h"
# include <signal.h>
# ifdef WIN32 # ifdef WIN32
# include <io.h> # include <io.h>
# endif # endif
#endif #endif
#include <boost/regex.hpp>
namespace fc { namespace rpc { namespace fc { namespace rpc {
static boost::regex& cli_regex_secret()
{
static boost::regex regex_expr;
return regex_expr;
}
static std::vector<std::string>& cli_commands() static std::vector<std::string>& cli_commands()
{ {
static std::vector<std::string>* cmds = new std::vector<std::string>(); static std::vector<std::string>* cmds = new std::vector<std::string>();
@ -54,6 +45,23 @@ void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ )
FC_ASSERT(false); 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<string(variant,const variants&)> formatter) void cli::format_result( const string& method, std::function<string(variant,const variants&)> formatter)
{ {
_result_formatters[method] = formatter; _result_formatters[method] = formatter;
@ -64,11 +72,6 @@ void cli::set_prompt( const string& prompt )
_prompt = prompt; _prompt = prompt;
} }
void cli::set_regex_secret( const string& expr )
{
cli_regex_secret() = expr;
}
void cli::run() void cli::run()
{ {
while( !_run_complete.canceled() ) while( !_run_complete.canceled() )
@ -82,17 +85,11 @@ void cli::run()
} }
catch ( const fc::eof_exception& e ) catch ( const fc::eof_exception& e )
{ {
_getline_thread = nullptr;
break; break;
} }
catch ( const fc::canceled_exception& e ) std::cout << line << "\n";
{
_getline_thread = nullptr;
break;
}
line += char(EOF); 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 ) if( args.size() == 0 )
continue; continue;
@ -109,16 +106,17 @@ void cli::run()
} }
catch ( const fc::exception& e ) catch ( const fc::exception& e )
{ {
std::cout << e.to_detail_string() << "\n";
if (e.code() == fc::canceled_exception_code) if (e.code() == fc::canceled_exception_code)
{ {
_getline_thread = nullptr;
break; break;
} }
std::cout << e.to_detail_string() << "\n";
} }
} }
} }
/**** /****
* @brief loop through list of commands, attempting to find a match * @brief loop through list of commands, attempting to find a match
* @param token what the user typed * @param token what the user typed
@ -127,52 +125,36 @@ void cli::run()
*/ */
static char *my_rl_complete(char *token, int *match) static char *my_rl_complete(char *token, int *match)
{ {
const auto& cmds = cli_commands(); bool have_one = false;
const size_t partlen = strlen (token); /* Part of token */ std::string method_name;
std::vector<std::reference_wrapper<const std::string>> matched_cmds; auto& cmd = cli_commands();
for( const std::string& it : cmds ) int partlen = strlen (token); /* Part of token */
{
if( it.compare(0, partlen, token) == 0 )
{
matched_cmds.push_back( it );
}
}
if( matched_cmds.size() == 0 ) for (const std::string& it : cmd)
{
if (it.compare(0, partlen, token) == 0)
{
if (have_one) {
// we can only have 1, but we found a second
return NULL; return NULL;
}
else
{
method_name = it;
have_one = true;
}
}
}
const std::string& first_matched_cmd = matched_cmds[0]; if (have_one)
if( matched_cmds.size() == 1 )
{ {
*match = 1; *match = 1;
std::string matched_cmd = first_matched_cmd + " "; method_name += " ";
return strdup( matched_cmd.c_str() + partlen ); return strdup (method_name.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 )
{
end = true;
break;
}
}
if( end )
break;
}
if( matched_len == partlen )
return NULL; return NULL;
std::string matched_cmd_part = first_matched_cmd.substr( partlen, matched_len - partlen );
return strdup( matched_cmd_part.c_str() );
} }
/*** /***
@ -194,7 +176,7 @@ static int cli_completion(char *token, char ***array)
} }
int total_matches = 0; int total_matches = 0;
const size_t partlen = strlen(token); int partlen = strlen(token);
for (const std::string& it : cmd) for (const std::string& it : cmd)
{ {
@ -209,98 +191,12 @@ static int cli_completion(char *token, char ***array)
return total_matches; 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 * @brief Read input from the user
* @param prompt the prompt to display * @param prompt the prompt to display
* @param line what the user typed * @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 // getting file descriptor for C++ streams is near impossible
// so we just assume it's the same as the C stream... // so we just assume it's the same as the C stream...
@ -316,35 +212,37 @@ void cli::getline( const std::string& prompt, std::string& line)
if( _isatty( _fileno( stdin ) ) ) if( _isatty( _fileno( stdin ) ) )
#endif #endif
{ {
if( _getline_thread ) rl_set_complete_func(my_rl_complete);
{ rl_set_list_possib_func(cli_completion);
_getline_thread->async( [&prompt,&line](){ jjkkljk;
static fc::thread getline_thread("getline");
getline_thread.async( [&](){
char* line_read = nullptr; char* line_read = nullptr;
std::cout.flush(); //readline doesn't use cin, so we must manually flush _out std::cout.flush(); //readline doesn't use cin, so we must manually flush _out
line_read = readline(prompt.c_str()); line_read = readline(prompt.c_str());
if( line_read == nullptr ) if( line_read == nullptr )
FC_THROW_EXCEPTION( fc::eof_exception, "" ); FC_THROW_EXCEPTION( fc::eof_exception, "" );
line = line_read; line = line_read;
// we don't need here to add line in editline's history, cause it will be doubled try
if (cli_check_secret(line_read)) { {
if (*line_read)
add_history(line_read);
}
catch(...)
{
free(line_read); free(line_read);
el_no_echo = 1; throw;
line_read = readline("Enter password: ");
el_no_echo = 0;
if( line_read == nullptr )
FC_THROW_EXCEPTION( fc::eof_exception, "" );
line = line + ' ' + line_read;
} }
free(line_read); free(line_read);
}).wait(); }).wait();
} }
}
else else
#endif #endif
{ {
std::cout << prompt; std::cout << prompt;
// sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline"); // sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline");
fc::getline( fc::cin, line ); fc::getline( fc::cin, line );
return;
} }
} }

View file

@ -147,16 +147,7 @@ namespace fc {
} }
void thread::debug( const fc::string& d ) { /*my->debug(d);*/ } void thread::debug( const fc::string& d ) { /*my->debug(d);*/ }
#if defined(__linux__) || defined(__APPLE__)
#include <signal.h>
#endif
void thread::signal(int sig)
{
#if defined(__linux__) || defined(__APPLE__)
pthread_kill( my->boost_thread->native_handle(), sig );
#endif
}
void thread::quit() void thread::quit()
{ {
//if quitting from a different thread, start quit task on thread. //if quitting from a different thread, start quit task on thread.