mirror of
https://github.com/monero-project/monero.git
synced 2025-01-28 18:56:31 +02:00
More work on making console command logic reusable
This commit is contained in:
parent
afaf97d7b7
commit
f3e6e2a529
@ -350,7 +350,6 @@ namespace epee
|
||||
return true;
|
||||
}*/
|
||||
|
||||
// TODO - Should this live somewhere else?
|
||||
class command_handler {
|
||||
public:
|
||||
typedef boost::function<bool (const std::vector<std::string> &)> callback;
|
||||
@ -403,32 +402,13 @@ namespace epee
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class console_handlers_binder
|
||||
class console_handlers_binder : public command_handler
|
||||
{
|
||||
typedef command_handler::callback console_command_handler;
|
||||
typedef command_handler::lookup command_handlers_map;
|
||||
command_handler m_command_handler;
|
||||
std::unique_ptr<boost::thread> m_console_thread;
|
||||
async_console_handler m_console_handler;
|
||||
public:
|
||||
std::string get_usage()
|
||||
{
|
||||
return m_command_handler.get_usage();
|
||||
}
|
||||
void set_handler(const std::string& cmd, const console_command_handler& hndlr, const std::string& usage = "")
|
||||
{
|
||||
m_command_handler.set_handler(cmd, hndlr, usage);
|
||||
}
|
||||
bool process_command_vec(const std::vector<std::string>& cmd)
|
||||
{
|
||||
return m_command_handler.process_command_vec(cmd);
|
||||
}
|
||||
|
||||
bool process_command_str(const std::string& cmd)
|
||||
{
|
||||
return m_command_handler.process_command_str(cmd);
|
||||
}
|
||||
|
||||
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, prompt, usage_string)));
|
||||
@ -447,32 +427,31 @@ namespace epee
|
||||
}
|
||||
};
|
||||
|
||||
/* work around because of broken boost bind */
|
||||
template<class t_server>
|
||||
class srv_console_handlers_binder: public console_handlers_binder
|
||||
{
|
||||
bool process_command_str(t_server* /*psrv*/, const std::string& cmd)
|
||||
{
|
||||
return console_handlers_binder::process_command_str(cmd);
|
||||
}
|
||||
public:
|
||||
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, prompt, usage_string)).detach();
|
||||
return true;
|
||||
}
|
||||
///* work around because of broken boost bind */
|
||||
//template<class t_server>
|
||||
//class srv_console_handlers_binder: public command_handler
|
||||
//{
|
||||
// async_console_handler m_console_handler;
|
||||
//public:
|
||||
// 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, prompt, usage_string)).detach();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& 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);
|
||||
}
|
||||
// bool run_handling(t_server* psrv, const std::string& prompt, const std::string& 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;
|
||||
};
|
||||
// void stop_handling()
|
||||
// {
|
||||
// m_console_handler.stop();
|
||||
// }
|
||||
//private:
|
||||
// bool process_command_str(t_server* /*psrv*/, const std::string& cmd)
|
||||
// {
|
||||
// return console_handlers_binder::process_command_str(cmd);
|
||||
// }
|
||||
//};
|
||||
}
|
||||
|
@ -1,90 +1,39 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "console_handler.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "common/util.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "version.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include <functional>
|
||||
|
||||
namespace daemonize {
|
||||
|
||||
class daemon_cmmands_handler
|
||||
namespace p = std::placeholders;
|
||||
using namespace epee;
|
||||
|
||||
class t_command_server_backend
|
||||
{
|
||||
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_srv;
|
||||
public:
|
||||
daemon_cmmands_handler(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv):m_srv(srv)
|
||||
{
|
||||
m_cmd_binder.set_handler("help", boost::bind(&daemon_cmmands_handler::help, this, _1), "Show this help");
|
||||
m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_cmmands_handler::print_pl, this, _1), "Print peer list");
|
||||
m_cmd_binder.set_handler("print_cn", boost::bind(&daemon_cmmands_handler::print_cn, this, _1), "Print connections");
|
||||
m_cmd_binder.set_handler("print_bc", boost::bind(&daemon_cmmands_handler::print_bc, this, _1), "Print blockchain info in a given blocks range, print_bc <begin_height> [<end_height>]");
|
||||
//m_cmd_binder.set_handler("print_bci", boost::bind(&daemon_cmmands_handler::print_bci, this, _1));
|
||||
//m_cmd_binder.set_handler("print_bc_outs", boost::bind(&daemon_cmmands_handler::print_bc_outs, this, _1));
|
||||
m_cmd_binder.set_handler("print_block", boost::bind(&daemon_cmmands_handler::print_block, this, _1), "Print block, print_block <block_hash> | <block_height>");
|
||||
m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_cmmands_handler::print_tx, this, _1), "Print transaction, print_tx <transaction_hash>");
|
||||
m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_cmmands_handler::start_mining, this, _1), "Start mining for specified address, start_mining <addr> [threads=1]");
|
||||
m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_cmmands_handler::stop_mining, this, _1), "Stop mining");
|
||||
m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_cmmands_handler::print_pool, this, _1), "Print transaction pool (long format)");
|
||||
m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_cmmands_handler::print_pool_sh, this, _1), "Print transaction pool (short format)");
|
||||
m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_cmmands_handler::show_hr, this, _1), "Start showing hash rate");
|
||||
m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_cmmands_handler::hide_hr, this, _1), "Stop showing hash rate");
|
||||
m_cmd_binder.set_handler("save", boost::bind(&daemon_cmmands_handler::save, this, _1), "Save blockchain");
|
||||
m_cmd_binder.set_handler("set_log", boost::bind(&daemon_cmmands_handler::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
|
||||
m_cmd_binder.set_handler("diff", boost::bind(&daemon_cmmands_handler::diff, this, _1), "Show difficulty");
|
||||
}
|
||||
|
||||
bool start_handling()
|
||||
{
|
||||
m_cmd_binder.start_handling(&m_srv, "", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop_handling()
|
||||
{
|
||||
m_cmd_binder.stop_handling();
|
||||
}
|
||||
|
||||
typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > t_node_server;
|
||||
private:
|
||||
epee::srv_console_handlers_binder<nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > > m_cmd_binder;
|
||||
t_node_server & m_srv;
|
||||
public:
|
||||
t_command_server_backend(t_node_server & srv) :
|
||||
m_srv(srv)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
std::string get_commands_str()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
||||
ss << "Commands: " << ENDL;
|
||||
std::string usage = m_cmd_binder.get_usage();
|
||||
boost::replace_all(usage, "\n", "\n ");
|
||||
usage.insert(0, " ");
|
||||
ss << usage << ENDL;
|
||||
return ss.str();
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool help(const std::vector<std::string>& args)
|
||||
{
|
||||
std::cout << get_commands_str() << ENDL;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_pl(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.log_peerlist();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool save(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.get_payload_object().get_core().get_blockchain_storage().store_blockchain();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool show_hr(const std::vector<std::string>& args)
|
||||
{
|
||||
if(!m_srv.get_payload_object().get_core().get_miner().is_mining())
|
||||
@ -96,13 +45,13 @@ private:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool hide_hr(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(false);
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool diff(const std::vector<std::string>& args)
|
||||
{
|
||||
cryptonote::difficulty_type difficulty = m_srv.get_payload_object().get_core().get_blockchain_storage().get_difficulty_for_next_block();
|
||||
@ -113,7 +62,7 @@ private:
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_bc_outs(const std::vector<std::string>& args)
|
||||
{
|
||||
if(args.size() != 1)
|
||||
@ -124,13 +73,13 @@ private:
|
||||
m_srv.get_payload_object().get_core().print_blockchain_outs(args[0]);
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_cn(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.get_payload_object().log_connections();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_bc(const std::vector<std::string>& args)
|
||||
{
|
||||
if(!args.size())
|
||||
@ -169,7 +118,7 @@ private:
|
||||
m_srv.get_payload_object().get_core().print_blockchain(start_index, end_index);
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_bci(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.get_payload_object().get_core().print_blockchain_index();
|
||||
@ -202,14 +151,13 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
static bool print_as_json(T& obj)
|
||||
{
|
||||
std::cout << cryptonote::obj_to_json_str(obj) << ENDL;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_block_by_height(uint64_t height)
|
||||
{
|
||||
std::list<cryptonote::block> blocks;
|
||||
@ -232,7 +180,7 @@ private:
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_block_by_hash(const std::string& arg)
|
||||
{
|
||||
crypto::hash block_hash;
|
||||
@ -260,7 +208,7 @@ private:
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_block(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty())
|
||||
@ -282,7 +230,7 @@ private:
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_tx(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty())
|
||||
@ -316,18 +264,19 @@ private:
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_pool(const std::vector<std::string>& args)
|
||||
{
|
||||
LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(false));
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool print_pool_sh(const std::vector<std::string>& args)
|
||||
{
|
||||
LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(true));
|
||||
return true;
|
||||
} //--------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
bool start_mining(const std::vector<std::string>& args)
|
||||
{
|
||||
if(!args.size())
|
||||
@ -355,10 +304,65 @@ private:
|
||||
m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count, attrs);
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
bool stop_mining(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.get_payload_object().get_core().get_miner().stop();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class t_command_server {
|
||||
private:
|
||||
t_command_server_backend m_backend;
|
||||
command_handler m_handler;
|
||||
public:
|
||||
t_command_server(t_command_server_backend::t_node_server & server) :
|
||||
m_backend(server)
|
||||
, m_handler()
|
||||
{
|
||||
m_handler.set_handler("help", std::bind(&t_command_server::help, this, p::_1), "Show this help");
|
||||
m_handler.set_handler("print_pl", std::bind(&t_command_server_backend::print_pl, &m_backend, p::_1), "Print peer list");
|
||||
m_handler.set_handler("print_cn", std::bind(&t_command_server_backend::print_cn, &m_backend, p::_1), "Print connections");
|
||||
m_handler.set_handler("print_bc", std::bind(&t_command_server_backend::print_bc, &m_backend, p::_1), "Print blockchain info in a given blocks range, print_bc <begin_height> [<end_height>]");
|
||||
//m_handler.set_handler("print_bci", std::bind(&t_command_server_backend::print_bci, &m_backend, p::_1));
|
||||
//m_handler.set_handler("print_bc_outs", std::bind(&t_command_server_backend::print_bc_outs, &m_backend, p::_1));
|
||||
m_handler.set_handler("print_block", std::bind(&t_command_server_backend::print_block, &m_backend, p::_1), "Print block, print_block <block_hash> | <block_height>");
|
||||
m_handler.set_handler("print_tx", std::bind(&t_command_server_backend::print_tx, &m_backend, p::_1), "Print transaction, print_tx <transaction_hash>");
|
||||
m_handler.set_handler("start_mining", std::bind(&t_command_server_backend::start_mining, &m_backend, p::_1), "Start mining for specified address, start_mining <addr> [threads=1]");
|
||||
m_handler.set_handler("stop_mining", std::bind(&t_command_server_backend::stop_mining, &m_backend, p::_1), "Stop mining");
|
||||
m_handler.set_handler("print_pool", std::bind(&t_command_server_backend::print_pool, &m_backend, p::_1), "Print transaction pool (long format)");
|
||||
m_handler.set_handler("print_pool_sh", std::bind(&t_command_server_backend::print_pool_sh, &m_backend, p::_1), "Print transaction pool (short format)");
|
||||
m_handler.set_handler("show_hr", std::bind(&t_command_server_backend::show_hr, &m_backend, p::_1), "Start showing hash rate");
|
||||
m_handler.set_handler("hide_hr", std::bind(&t_command_server_backend::hide_hr, &m_backend, p::_1), "Stop showing hash rate");
|
||||
m_handler.set_handler("save", std::bind(&t_command_server_backend::save, &m_backend, p::_1), "Save blockchain");
|
||||
m_handler.set_handler("set_log", std::bind(&t_command_server_backend::set_log, &m_backend, p::_1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
|
||||
m_handler.set_handler("diff", std::bind(&t_command_server_backend::diff, &m_backend, p::_1), "Show difficulty");
|
||||
}
|
||||
|
||||
bool process_command(const std::string& cmd)
|
||||
{
|
||||
return m_handler.process_command_str(cmd);
|
||||
}
|
||||
|
||||
private:
|
||||
bool help(const std::vector<std::string>& args)
|
||||
{
|
||||
std::cout << get_commands_str() << ENDL;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string get_commands_str()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
||||
ss << "Commands: " << ENDL;
|
||||
std::string usage = m_handler.get_usage();
|
||||
boost::replace_all(usage, "\n", "\n ");
|
||||
usage.insert(0, " ");
|
||||
ss << usage << ENDL;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace daemonize
|
51
src/daemon/console_command_thread.h
Normal file
51
src/daemon/console_command_thread.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "console_handler.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "daemon/command_server.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include <functional>
|
||||
|
||||
namespace daemonize {
|
||||
|
||||
class t_console_command_thread
|
||||
{
|
||||
public:
|
||||
typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > t_server;
|
||||
private:
|
||||
t_command_server m_server;
|
||||
t_server & m_srv;
|
||||
async_console_handler m_console_handler;
|
||||
public:
|
||||
t_console_command_thread(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv) :
|
||||
m_server(srv)
|
||||
, m_srv(srv)
|
||||
, m_console_handler()
|
||||
{}
|
||||
|
||||
void start()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
auto process_command_callback = [this](t_server* /*psrv*/, const std::string& cmd) {
|
||||
return m_server.process_command(cmd);
|
||||
};
|
||||
|
||||
auto loop = [this, process_command_callback]() {
|
||||
m_console_handler.run(&m_srv, process_command_callback, "", "");
|
||||
};
|
||||
std::thread(loop).detach();
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
m_console_handler.stop();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace daemonize
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "version.h"
|
||||
#include "daemon/console_command_thread.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
@ -21,13 +22,17 @@ using namespace epee;
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "rpc/core_rpc_server.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "daemon_commands_handler.h"
|
||||
#include "version.h"
|
||||
|
||||
//#if !defined(WIN32)
|
||||
//#include "posix_daemonize.h"
|
||||
//#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
using namespace daemonize;
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
@ -43,14 +48,14 @@ namespace
|
||||
const command_line::arg_descriptor<bool> arg_stop_daemon = {"stop", "Stop running daemon"};
|
||||
const command_line::arg_descriptor<bool> arg_help_daemon = {"daemon-help", "Display daemon command help"};
|
||||
const command_line::arg_descriptor<std::string> arg_daemon_command = {"send-command", "Send a command string to the running daemon"};
|
||||
}
|
||||
|
||||
bool is_there_more_than_one(po::variables_map vm, std::initializer_list<std::string> arg_names) {
|
||||
bool is_there_more_than_one(po::variables_map vm, std::initializer_list<std::string> arg_names) {
|
||||
int count = 0;
|
||||
for (auto & arg_name : arg_names) {
|
||||
if (vm[arg_name].empty() || !vm[arg_name].defaulted()) ++count;
|
||||
}
|
||||
return count > 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@ -226,7 +231,7 @@ int main(int argc, char* argv[])
|
||||
cryptonote::core_rpc_server rpc_server(ccore, p2psrv);
|
||||
cprotocol.set_p2p_endpoint(&p2psrv);
|
||||
ccore.set_cryptonote_protocol(&cprotocol);
|
||||
daemon_cmmands_handler dch(p2psrv);
|
||||
t_console_command_thread console_command_thread(p2psrv);
|
||||
|
||||
//initialize objects
|
||||
LOG_PRINT_L0("Initializing p2p server...");
|
||||
@ -253,7 +258,7 @@ int main(int argc, char* argv[])
|
||||
// start components
|
||||
if(!command_line::has_arg(vm, arg_console))
|
||||
{
|
||||
dch.start_handling();
|
||||
console_command_thread.start();
|
||||
}
|
||||
|
||||
LOG_PRINT_L0("Starting core rpc server...");
|
||||
@ -261,8 +266,8 @@ int main(int argc, char* argv[])
|
||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
|
||||
LOG_PRINT_L0("Core rpc server started ok");
|
||||
|
||||
tools::signal_handler::install([&dch, &p2psrv] {
|
||||
dch.stop_handling();
|
||||
tools::signal_handler::install([&console_command_thread, &p2psrv] {
|
||||
console_command_thread.stop();
|
||||
p2psrv.send_stop_signal();
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user