More work on making console command logic reusable

This commit is contained in:
Zachary Michaels 2014-06-17 16:46:41 -04:00
parent afaf97d7b7
commit f3e6e2a529
4 changed files with 186 additions and 147 deletions

View File

@ -350,7 +350,6 @@ namespace epee
return true; return true;
}*/ }*/
// TODO - Should this live somewhere else?
class command_handler { class command_handler {
public: public:
typedef boost::function<bool (const std::vector<std::string> &)> callback; 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::callback console_command_handler;
typedef command_handler::lookup command_handlers_map; typedef command_handler::lookup command_handlers_map;
command_handler m_command_handler;
std::unique_ptr<boost::thread> m_console_thread; std::unique_ptr<boost::thread> m_console_thread;
async_console_handler m_console_handler; async_console_handler m_console_handler;
public: 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 = "") 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))); 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 */ ///* work around because of broken boost bind */
template<class t_server> //template<class t_server>
class srv_console_handlers_binder: public console_handlers_binder //class srv_console_handlers_binder: public command_handler
{ //{
bool process_command_str(t_server* /*psrv*/, const std::string& cmd) // async_console_handler m_console_handler;
{ //public:
return console_handlers_binder::process_command_str(cmd); // bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "")
} // {
public: // boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "") // return true;
{ // }
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) // 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); // 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() // void stop_handling()
{ // {
m_console_handler.stop(); // m_console_handler.stop();
} // }
//private:
private: // bool process_command_str(t_server* /*psrv*/, const std::string& cmd)
async_console_handler m_console_handler; // {
}; // return console_handlers_binder::process_command_str(cmd);
// }
//};
} }

View File

@ -1,108 +1,57 @@
// 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 #pragma once
#include <boost/lexical_cast.hpp>
#include "console_handler.h" #include "console_handler.h"
#include "p2p/net_node.h"
#include "cryptonote_core/cryptonote_core.h" #include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "common/util.h" #include "p2p/net_node.h"
#include "crypto/hash.h" #include <functional>
#include "version.h"
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: public:
daemon_cmmands_handler(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& srv):m_srv(srv) typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > t_node_server;
{
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();
}
private: 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) bool print_pl(const std::vector<std::string>& args)
{ {
m_srv.log_peerlist(); m_srv.log_peerlist();
return true; return true;
} }
//--------------------------------------------------------------------------------
bool save(const std::vector<std::string>& args) bool save(const std::vector<std::string>& args)
{ {
m_srv.get_payload_object().get_core().get_blockchain_storage().store_blockchain(); m_srv.get_payload_object().get_core().get_blockchain_storage().store_blockchain();
return true; return true;
} }
//--------------------------------------------------------------------------------
bool show_hr(const std::vector<std::string>& args) bool show_hr(const std::vector<std::string>& args)
{ {
if(!m_srv.get_payload_object().get_core().get_miner().is_mining()) if(!m_srv.get_payload_object().get_core().get_miner().is_mining())
{ {
std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL; std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL;
} else } else
{ {
m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true); m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true);
} }
return true; return true;
} }
//--------------------------------------------------------------------------------
bool hide_hr(const std::vector<std::string>& args) bool hide_hr(const std::vector<std::string>& args)
{ {
m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(false); m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(false);
return true; return true;
} }
//--------------------------------------------------------------------------------
bool diff(const std::vector<std::string>& args) 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(); 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; return true;
} }
//--------------------------------------------------------------------------------
bool print_bc_outs(const std::vector<std::string>& args) bool print_bc_outs(const std::vector<std::string>& args)
{ {
if(args.size() != 1) if(args.size() != 1)
@ -124,13 +73,13 @@ private:
m_srv.get_payload_object().get_core().print_blockchain_outs(args[0]); m_srv.get_payload_object().get_core().print_blockchain_outs(args[0]);
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_cn(const std::vector<std::string>& args) bool print_cn(const std::vector<std::string>& args)
{ {
m_srv.get_payload_object().log_connections(); m_srv.get_payload_object().log_connections();
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_bc(const std::vector<std::string>& args) bool print_bc(const std::vector<std::string>& args)
{ {
if(!args.size()) if(!args.size())
@ -169,7 +118,7 @@ private:
m_srv.get_payload_object().get_core().print_blockchain(start_index, end_index); m_srv.get_payload_object().get_core().print_blockchain(start_index, end_index);
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_bci(const std::vector<std::string>& args) bool print_bci(const std::vector<std::string>& args)
{ {
m_srv.get_payload_object().get_core().print_blockchain_index(); m_srv.get_payload_object().get_core().print_blockchain_index();
@ -202,14 +151,13 @@ private:
return true; return true;
} }
//--------------------------------------------------------------------------------
template <typename T> template <typename T>
static bool print_as_json(T& obj) static bool print_as_json(T& obj)
{ {
std::cout << cryptonote::obj_to_json_str(obj) << ENDL; std::cout << cryptonote::obj_to_json_str(obj) << ENDL;
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_block_by_height(uint64_t height) bool print_block_by_height(uint64_t height)
{ {
std::list<cryptonote::block> blocks; std::list<cryptonote::block> blocks;
@ -232,7 +180,7 @@ private:
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_block_by_hash(const std::string& arg) bool print_block_by_hash(const std::string& arg)
{ {
crypto::hash block_hash; crypto::hash block_hash;
@ -260,7 +208,7 @@ private:
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_block(const std::vector<std::string>& args) bool print_block(const std::vector<std::string>& args)
{ {
if (args.empty()) if (args.empty())
@ -282,7 +230,7 @@ private:
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_tx(const std::vector<std::string>& args) bool print_tx(const std::vector<std::string>& args)
{ {
if (args.empty()) if (args.empty())
@ -316,18 +264,19 @@ private:
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_pool(const std::vector<std::string>& args) 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)); LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(false));
return true; return true;
} }
//--------------------------------------------------------------------------------
bool print_pool_sh(const std::vector<std::string>& args) 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)); LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(true));
return true; return true;
} //-------------------------------------------------------------------------------- }
bool start_mining(const std::vector<std::string>& args) bool start_mining(const std::vector<std::string>& args)
{ {
if(!args.size()) if(!args.size())
@ -355,10 +304,65 @@ private:
m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count, attrs); m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count, attrs);
return true; return true;
} }
//--------------------------------------------------------------------------------
bool stop_mining(const std::vector<std::string>& args) bool stop_mining(const std::vector<std::string>& args)
{ {
m_srv.get_payload_object().get_core().get_miner().stop(); m_srv.get_payload_object().get_core().get_miner().stop();
return true; 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

View 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

View File

@ -8,6 +8,7 @@
#include "include_base_utils.h" #include "include_base_utils.h"
#include "version.h" #include "version.h"
#include "daemon/console_command_thread.h"
using namespace epee; using namespace epee;
@ -21,13 +22,17 @@ using namespace epee;
#include "cryptonote_core/cryptonote_core.h" #include "cryptonote_core/cryptonote_core.h"
#include "rpc/core_rpc_server.h" #include "rpc/core_rpc_server.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.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) #if defined(WIN32)
#include <crtdbg.h> #include <crtdbg.h>
#endif #endif
using namespace daemonize;
namespace po = boost::program_options; namespace po = boost::program_options;
namespace bf = boost::filesystem; 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_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<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"}; 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; int count = 0;
for (auto & arg_name : arg_names) { for (auto & arg_name : arg_names) {
if (vm[arg_name].empty() || !vm[arg_name].defaulted()) ++count; if (vm[arg_name].empty() || !vm[arg_name].defaulted()) ++count;
}
return count > 1;
} }
return count > 1;
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
@ -226,7 +231,7 @@ int main(int argc, char* argv[])
cryptonote::core_rpc_server rpc_server(ccore, p2psrv); cryptonote::core_rpc_server rpc_server(ccore, p2psrv);
cprotocol.set_p2p_endpoint(&p2psrv); cprotocol.set_p2p_endpoint(&p2psrv);
ccore.set_cryptonote_protocol(&cprotocol); ccore.set_cryptonote_protocol(&cprotocol);
daemon_cmmands_handler dch(p2psrv); t_console_command_thread console_command_thread(p2psrv);
//initialize objects //initialize objects
LOG_PRINT_L0("Initializing p2p server..."); LOG_PRINT_L0("Initializing p2p server...");
@ -253,7 +258,7 @@ int main(int argc, char* argv[])
// start components // start components
if(!command_line::has_arg(vm, arg_console)) if(!command_line::has_arg(vm, arg_console))
{ {
dch.start_handling(); console_command_thread.start();
} }
LOG_PRINT_L0("Starting core rpc server..."); 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."); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
LOG_PRINT_L0("Core rpc server started ok"); LOG_PRINT_L0("Core rpc server started ok");
tools::signal_handler::install([&dch, &p2psrv] { tools::signal_handler::install([&console_command_thread, &p2psrv] {
dch.stop_handling(); console_command_thread.stop();
p2psrv.send_stop_signal(); p2psrv.send_stop_signal();
}); });