Fix signal handling in CLI
This commit is contained in:
parent
127aadbffc
commit
ed3f1c86dd
2 changed files with 81 additions and 28 deletions
|
|
@ -25,6 +25,7 @@ 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);
|
||||||
|
|
||||||
|
|
@ -40,5 +41,6 @@ namespace fc { namespace rpc {
|
||||||
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
|
||||||
};
|
};
|
||||||
} }
|
} }
|
||||||
|
|
|
||||||
107
src/rpc/cli.cpp
107
src/rpc/cli.cpp
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#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
|
||||||
|
|
@ -53,23 +54,24 @@ 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);
|
|
||||||
|
|
||||||
#ifdef HAVE_EDITLINE
|
|
||||||
el_hist_size = 256;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_run_complete = fc::async( [&](){ run(); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
void cli::stop()
|
void cli::stop()
|
||||||
{
|
{
|
||||||
_run_complete.cancel();
|
cancel();
|
||||||
_run_complete.wait();
|
_run_complete.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cli::cancel()
|
||||||
|
{
|
||||||
|
_run_complete.cancel();
|
||||||
|
#ifdef HAVE_EDITLINE
|
||||||
|
if( _getline_thread )
|
||||||
|
{
|
||||||
|
_getline_thread->signal(SIGINT);
|
||||||
|
_getline_thread = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void cli::wait()
|
void cli::wait()
|
||||||
{
|
{
|
||||||
_run_complete.wait();
|
_run_complete.wait();
|
||||||
|
|
@ -103,6 +105,20 @@ void cli::run()
|
||||||
}
|
}
|
||||||
catch ( const fc::eof_exception& e )
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,6 +144,11 @@ void cli::run()
|
||||||
|
|
||||||
if (e.code() == fc::canceled_exception_code)
|
if (e.code() == fc::canceled_exception_code)
|
||||||
{
|
{
|
||||||
|
if( _getline_thread )
|
||||||
|
{
|
||||||
|
_getline_thread->quit();
|
||||||
|
_getline_thread = nullptr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -237,6 +258,39 @@ static int cli_check_secret(const char *source)
|
||||||
return 0;
|
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
|
* @brief Read input from the user
|
||||||
* @param prompt the prompt to display
|
* @param prompt the prompt to display
|
||||||
|
|
@ -258,21 +312,19 @@ void cli::getline( const fc::string& prompt, fc::string& line)
|
||||||
if( _isatty( _fileno( stdin ) ) )
|
if( _isatty( _fileno( stdin ) ) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
rl_set_complete_func(my_rl_complete);
|
if( _getline_thread )
|
||||||
rl_set_list_possib_func(cli_completion);
|
{
|
||||||
rl_set_check_secret_func(cli_check_secret);
|
_getline_thread->async( [&prompt,&line](){
|
||||||
|
char* line_read = nullptr;
|
||||||
static fc::thread getline_thread("getline");
|
std::cout.flush(); //readline doesn't use cin, so we must manually flush _out
|
||||||
getline_thread.async( [&](){
|
line_read = readline(prompt.c_str());
|
||||||
char* line_read = nullptr;
|
if( line_read == nullptr )
|
||||||
std::cout.flush(); //readline doesn't use cin, so we must manually flush _out
|
FC_THROW_EXCEPTION( fc::eof_exception, "" );
|
||||||
line_read = readline(prompt.c_str());
|
line = line_read;
|
||||||
if( line_read == nullptr )
|
// we don't need here to add line in editline's history, cause it will be doubled
|
||||||
FC_THROW_EXCEPTION( fc::eof_exception, "" );
|
free(line_read);
|
||||||
line = line_read;
|
}).wait();
|
||||||
// we don't need here to add line in editline's history, cause it will be doubled
|
}
|
||||||
free(line_read);
|
|
||||||
}).wait();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -280,7 +332,6 @@ void cli::getline( const fc::string& prompt, fc::string& line)
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue