mirror of
https://github.com/monero-project/monero.git
synced 2025-05-06 14:25:01 -04:00
some fixes
This commit is contained in:
parent
296ae46ed8
commit
8efa1313f3
67 changed files with 1523 additions and 757 deletions
|
@ -1,6 +1,6 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
|
@ -11,7 +11,7 @@
|
|||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
@ -22,16 +22,187 @@
|
|||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class async_stdin_reader
|
||||
{
|
||||
public:
|
||||
async_stdin_reader()
|
||||
: m_run(true)
|
||||
, m_has_read_request(false)
|
||||
, m_read_status(state_init)
|
||||
{
|
||||
m_reader_thread = std::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
|
||||
}
|
||||
|
||||
~async_stdin_reader()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
// Not thread safe. Only one thread can call this method at once.
|
||||
bool get_line(std::string& line)
|
||||
{
|
||||
if (!start_read())
|
||||
return false;
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_response_mutex);
|
||||
while (state_init == m_read_status)
|
||||
{
|
||||
m_response_cv.wait(lock);
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
if (state_success == m_read_status)
|
||||
{
|
||||
line = m_line;
|
||||
res = true;
|
||||
}
|
||||
|
||||
m_read_status = state_init;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (m_run)
|
||||
{
|
||||
m_run.store(false, std::memory_order_relaxed);
|
||||
|
||||
#if defined(WIN32)
|
||||
::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE));
|
||||
#endif
|
||||
|
||||
m_request_cv.notify_one();
|
||||
m_reader_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool start_read()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_request_mutex);
|
||||
if (!m_run.load(std::memory_order_relaxed) || m_has_read_request)
|
||||
return false;
|
||||
|
||||
m_has_read_request = true;
|
||||
m_request_cv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wait_read()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_request_mutex);
|
||||
while (m_run.load(std::memory_order_relaxed) && !m_has_read_request)
|
||||
{
|
||||
m_request_cv.wait(lock);
|
||||
}
|
||||
|
||||
if (m_has_read_request)
|
||||
{
|
||||
m_has_read_request = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wait_stdin_data()
|
||||
{
|
||||
#if !defined(WIN32)
|
||||
int stdin_fileno = ::fileno(stdin);
|
||||
|
||||
while (m_run.load(std::memory_order_relaxed))
|
||||
{
|
||||
fd_set read_set;
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(stdin_fileno, &read_set);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100 * 1000;
|
||||
|
||||
int retval = ::select(stdin_fileno + 1, &read_set, NULL, NULL, &tv);
|
||||
if (retval < 0)
|
||||
return false;
|
||||
else if (0 < retval)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void reader_thread_func()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!wait_read())
|
||||
break;
|
||||
|
||||
std::string line;
|
||||
bool read_ok = true;
|
||||
if (wait_stdin_data())
|
||||
{
|
||||
if (m_run.load(std::memory_order_relaxed))
|
||||
{
|
||||
std::getline(std::cin, line);
|
||||
read_ok = !std::cin.eof() && !std::cin.fail();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_ok = false;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_response_mutex);
|
||||
if (m_run.load(std::memory_order_relaxed))
|
||||
{
|
||||
m_line = std::move(line);
|
||||
m_read_status = read_ok ? state_success : state_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_read_status = state_cancelled;
|
||||
}
|
||||
m_response_cv.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum t_state
|
||||
{
|
||||
state_init,
|
||||
state_success,
|
||||
state_error,
|
||||
state_cancelled
|
||||
};
|
||||
|
||||
private:
|
||||
std::thread m_reader_thread;
|
||||
std::atomic<bool> m_run;
|
||||
|
||||
std::string m_line;
|
||||
bool m_has_read_request;
|
||||
t_state m_read_status;
|
||||
|
||||
std::mutex m_request_mutex;
|
||||
std::mutex m_response_mutex;
|
||||
std::condition_variable m_request_cv;
|
||||
std::condition_variable m_response_cv;
|
||||
};
|
||||
|
||||
|
||||
template<class t_server>
|
||||
|
@ -39,124 +210,113 @@ namespace epee
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class t_server, class chain_handler>
|
||||
bool default_console_handler(t_server* psrv, chain_handler ch_handler, const std::string usage = "")
|
||||
|
||||
class async_console_handler
|
||||
{
|
||||
TRY_ENTRY();
|
||||
bool continue_handle = true;
|
||||
while(continue_handle)
|
||||
public:
|
||||
async_console_handler()
|
||||
{
|
||||
char command_buff[400] = {0};
|
||||
std::string command;
|
||||
std::cin.getline(command_buff, 399);
|
||||
if(std::cin.eof() || std::cin.fail())
|
||||
{
|
||||
LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0);
|
||||
continue_handle = false;
|
||||
break;
|
||||
}
|
||||
command = command_buff;
|
||||
|
||||
if(!command.compare("exit") || !command.compare("q") )
|
||||
{
|
||||
psrv->send_stop_signal();
|
||||
continue_handle = false;
|
||||
}else if ( !command.compare(0, 7, "set_log"))
|
||||
{
|
||||
//parse set_log command
|
||||
if(command.size() != 9)
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
int n = 0;
|
||||
if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
log_space::get_set_log_detalisation_level(true, n);
|
||||
LOG_PRINT_L0("New log level set " << n);
|
||||
}
|
||||
else if(ch_handler(psrv, command))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
std::cout << "unknown command: " << command << std::endl;
|
||||
std::cout << usage;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
CATCH_ENTRY_L0("console_handler", false);
|
||||
}
|
||||
|
||||
template<class chain_handler>
|
||||
bool default_console_handler2(chain_handler ch_handler, const std::string usage)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
bool continue_handle = true;
|
||||
while(continue_handle)
|
||||
template<class t_server, class chain_handler>
|
||||
bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
|
||||
{
|
||||
char command_buff[400] = {0};
|
||||
std::string command;
|
||||
std::cin.getline(command_buff, 399);
|
||||
if(std::cin.eof() || std::cin.fail())
|
||||
{
|
||||
|
||||
LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0);
|
||||
continue_handle = false;
|
||||
break;
|
||||
}
|
||||
command = command_buff;
|
||||
|
||||
if(!command.compare("exit") || !command.compare("q") )
|
||||
{
|
||||
continue_handle = false;
|
||||
}else if ( !command.compare(0, 7, "set_log"))
|
||||
{
|
||||
//parse set_log command
|
||||
if(command.size() != 9)
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
int n = 0;
|
||||
if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
log_space::get_set_log_detalisation_level(true, n);
|
||||
LOG_PRINT_L0("New log level set " << n);
|
||||
}
|
||||
else if(ch_handler(command))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
std::cout << "unknown command: " << command << std::endl;
|
||||
std::cout << usage;
|
||||
}
|
||||
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
|
||||
}
|
||||
return true;
|
||||
CATCH_ENTRY_L0("console_handler", false);
|
||||
}
|
||||
|
||||
|
||||
template<class chain_handler>
|
||||
bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
|
||||
{
|
||||
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, [] { });
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
m_stdin_reader.stop();
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename t_cmd_handler, typename t_exit_handler>
|
||||
bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, const t_exit_handler& exit_handler)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
bool continue_handle = true;
|
||||
while(continue_handle)
|
||||
{
|
||||
if (!prompt.empty())
|
||||
{
|
||||
epee::log_space::set_console_color(epee::log_space::console_color_yellow, true);
|
||||
std::cout << prompt;
|
||||
if (' ' != prompt.back())
|
||||
std::cout << ' ';
|
||||
epee::log_space::reset_console_color();
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
std::string command;
|
||||
if(!m_stdin_reader.get_line(command))
|
||||
{
|
||||
LOG_PRINT("Failed to read line. Stopping...", LOG_LEVEL_0);
|
||||
continue_handle = false;
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_PRINT_L2("Read command: " << command);
|
||||
if(0 == command.compare("exit") || 0 == command.compare("q"))
|
||||
{
|
||||
continue_handle = false;
|
||||
}else if (!command.compare(0, 7, "set_log"))
|
||||
{
|
||||
//parse set_log command
|
||||
if(command.size() != 9)
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
uint16_t n = 0;
|
||||
if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
log_space::get_set_log_detalisation_level(true, n);
|
||||
LOG_PRINT_L0("New log level set " << n);
|
||||
}else if (command.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(cmd_handler(command))
|
||||
{
|
||||
continue;
|
||||
} else
|
||||
{
|
||||
std::cout << "unknown command: " << command << std::endl;
|
||||
std::cout << usage;
|
||||
}
|
||||
}
|
||||
exit_handler();
|
||||
return true;
|
||||
CATCH_ENTRY_L0("console_handler", false);
|
||||
}
|
||||
|
||||
private:
|
||||
async_stdin_reader m_stdin_reader;
|
||||
};
|
||||
|
||||
|
||||
template<class t_server, class t_handler>
|
||||
bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
|
||||
bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
boost::thread( boost::bind(default_console_handler<t_server, t_handler>, ptsrv, handlr, usage) );
|
||||
std::shared_ptr<async_console_handler> console_handler = std::make_shared<async_console_handler>();
|
||||
boost::thread(boost::bind(&async_console_handler::run<t_server, t_handler>, console_handler, ptsrv, handlr, prompt, usage)).detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class t_server>
|
||||
bool start_default_console(t_server* ptsrv, const std::string& usage = "")
|
||||
bool start_default_console(t_server* ptsrv, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
return start_default_console(ptsrv, empty_commands_handler<t_server>, usage);
|
||||
return start_default_console(ptsrv, empty_commands_handler<t_server>, prompt, usage);
|
||||
}
|
||||
|
||||
template<class t_server, class t_handler>
|
||||
|
@ -166,15 +326,16 @@ namespace epee
|
|||
}
|
||||
|
||||
template<class t_server, class t_handler>
|
||||
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
|
||||
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
return default_console_handler(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), usage);
|
||||
async_console_handler console_handler;
|
||||
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
|
||||
}
|
||||
|
||||
template<class t_server, class t_handler>
|
||||
bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
|
||||
bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, usage) );
|
||||
boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -209,7 +370,8 @@ namespace epee
|
|||
typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
|
||||
std::unique_ptr<boost::thread> m_console_thread;
|
||||
command_handlers_map m_command_handlers;
|
||||
public:
|
||||
async_console_handler m_console_handler;
|
||||
public:
|
||||
std::string get_usage()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
@ -217,7 +379,7 @@ namespace epee
|
|||
for(auto& x:m_command_handlers)
|
||||
if(x.first.size() > max_command_len)
|
||||
max_command_len = x.first.size();
|
||||
|
||||
|
||||
for(auto& x:m_command_handlers)
|
||||
{
|
||||
ss.width(max_command_len + 3);
|
||||
|
@ -255,24 +417,22 @@ namespace epee
|
|||
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
|
||||
return true;
|
||||
}*/
|
||||
|
||||
bool start_handling(const std::string& usage_string = "")
|
||||
|
||||
bool start_handling(const std::string& prompt, const std::string& usage_string = "")
|
||||
{
|
||||
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, usage_string) ));
|
||||
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string)));
|
||||
m_console_thread->detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stop_handling()
|
||||
void stop_handling()
|
||||
{
|
||||
if(m_console_thread.get())
|
||||
m_console_thread->interrupt();
|
||||
return true;
|
||||
m_console_handler.stop();
|
||||
}
|
||||
|
||||
|
||||
bool run_handling(const std::string usage_string)
|
||||
bool run_handling(const std::string& prompt, const std::string& usage_string)
|
||||
{
|
||||
return default_console_handler2(boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string);
|
||||
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string);
|
||||
}
|
||||
|
||||
/*template<class t_srv>
|
||||
|
@ -280,7 +440,6 @@ namespace epee
|
|||
{
|
||||
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
|
||||
}*/
|
||||
|
||||
};
|
||||
|
||||
/* work around because of broken boost bind */
|
||||
|
@ -292,19 +451,23 @@ namespace epee
|
|||
return console_handlers_binder::process_command_str(cmd);
|
||||
}
|
||||
public:
|
||||
bool start_handling(t_server* psrv, const std::string& usage_string = "")
|
||||
bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "")
|
||||
{
|
||||
boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, usage_string) );
|
||||
boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_handling(t_server* psrv, const std::string usage_string)
|
||||
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string)
|
||||
{
|
||||
return default_console_handler(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), usage_string);
|
||||
return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
|
||||
}
|
||||
|
||||
void stop_handling()
|
||||
{
|
||||
m_console_handler.stop();
|
||||
}
|
||||
|
||||
private:
|
||||
async_console_handler m_console_handler;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue