diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 5e4f9c7e..45b8e66b 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -924,7 +924,8 @@ namespace detail { std::shared_ptr _websocket_server; std::shared_ptr _websocket_tls_server; - std::map> _plugins; + std::map> _active_plugins; + std::map> _available_plugins; bool _is_finished_syncing = false; }; @@ -963,6 +964,7 @@ void application::set_program_options(boost::program_options::options_descriptio ("genesis-json", bpo::value(), "File to read Genesis State from") ("dbg-init-key", bpo::value(), "Block signing key to use for init witnesses, overrides genesis file") ("api-access", bpo::value(), "JSON file specifying API permissions") + ("plugins", bpo::value(), "Space-separated list of plugins to activate") ; command_line_options.add(configuration_file_options); command_line_options.add_options() @@ -1008,6 +1010,22 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti std::exit(EXIT_SUCCESS); } + + std::vector wanted; + if( options.count("plugins") ) + { + boost::split(wanted, options.at("plugins").as(), [](char c){return c == ' ';}); + } + else + { + wanted.push_back("witness"); + wanted.push_back("account_history"); + wanted.push_back("market_history"); + } + for (auto& it : wanted) + { + if (!it.empty()) enable_plugin(it); + } } void application::startup() @@ -1025,7 +1043,7 @@ void application::startup() std::shared_ptr application::get_plugin(const string& name) const { - return my->_plugins[name]; + return my->_active_plugins[name]; } net::node_ptr application::p2p_node() @@ -1058,14 +1076,20 @@ bool application::is_finished_syncing() const return my->_is_finished_syncing; } -void graphene::app::application::add_plugin(const string& name, std::shared_ptr p) +void graphene::app::application::enable_plugin(const string& name) { - my->_plugins[name] = p; + FC_ASSERT(my->_available_plugins[name], "Unknown plugin '" + name + "'"); + my->_active_plugins[name] = my->_available_plugins[name]; + my->_active_plugins[name]->plugin_set_app(this); +} + +void graphene::app::application::add_available_plugin(std::shared_ptr p) { + my->_available_plugins[p->plugin_name()] = p; } void application::shutdown_plugins() { - for( auto& entry : my->_plugins ) + for( auto& entry : my->_active_plugins ) entry.second->plugin_shutdown(); return; } @@ -1079,14 +1103,14 @@ void application::shutdown() void application::initialize_plugins( const boost::program_options::variables_map& options ) { - for( auto& entry : my->_plugins ) + for( auto& entry : my->_active_plugins ) entry.second->plugin_initialize( options ); return; } void application::startup_plugins() { - for( auto& entry : my->_plugins ) + for( auto& entry : my->_active_plugins ) entry.second->plugin_startup(); return; } diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index f5172144..ba07e80a 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -96,7 +96,8 @@ namespace graphene { namespace app { boost::signals2::signal syncing_finished; private: - void add_plugin( const string& name, std::shared_ptr p ); + void enable_plugin( const string& name ); + void add_available_plugin( std::shared_ptr p ); std::shared_ptr my; boost::program_options::options_description _cli_options; diff --git a/libraries/plugins/delayed_node/delayed_node_plugin.cpp b/libraries/plugins/delayed_node/delayed_node_plugin.cpp index fb70cb68..a73e5923 100644 --- a/libraries/plugins/delayed_node/delayed_node_plugin.cpp +++ b/libraries/plugins/delayed_node/delayed_node_plugin.cpp @@ -58,7 +58,7 @@ delayed_node_plugin::~delayed_node_plugin() void delayed_node_plugin::plugin_set_program_options(bpo::options_description& cli, bpo::options_description& cfg) { cli.add_options() - ("trusted-node", boost::program_options::value()->required(), "RPC endpoint of a trusted validating node (required)") + ("trusted-node", boost::program_options::value(), "RPC endpoint of a trusted validating node (required)") ; cfg.add(cli); } @@ -74,6 +74,7 @@ void delayed_node_plugin::connect() void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options) { + FC_ASSERT(options.count("trusted-node") > 0); my->remote_endpoint = "ws://" + options.at("trusted-node").as(); } diff --git a/programs/delayed_node/main.cpp b/programs/delayed_node/main.cpp index 74cd8fc3..44d12f37 100644 --- a/programs/delayed_node/main.cpp +++ b/programs/delayed_node/main.cpp @@ -70,10 +70,19 @@ int main(int argc, char** argv) { bpo::variables_map options; + bpo::options_description cli, cfg; + node.set_program_options(cli, cfg); + cfg_options.add(cfg); + + cfg_options.add_options() + ("plugins", bpo::value()->default_value("delayed_node account_history market_history"), + "Space-separated list of plugins to activate"); + auto delayed_plug = node.register_plugin(); auto history_plug = node.register_plugin(); auto market_history_plug = node.register_plugin(); + // add plugin options to config try { bpo::options_description cli, cfg; @@ -160,6 +169,9 @@ int main(int argc, char** argv) { elog("Error parsing configuration file: ${e}", ("e", e.what())); return 1; } + if( !options.count("plugins") ) + options.insert( std::make_pair( "plugins", bpo::variable_value(std::string("delayed_node account_history market_history"), true) ) ); + node.initialize(data_dir, options); node.initialize_plugins( options ); diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index c9a09ca3..93ba86b5 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -78,12 +78,23 @@ int main(int argc, char** argv) { bpo::options_description cfg_options("Graphene Witness Node"); app_options.add_options() ("help,h", "Print this help message and exit.") - ("version", "Display the version info and exit") - ("data-dir,d", bpo::value()->default_value("witness_node_data_dir"), "Directory containing databases, configuration file, etc.") - ; + ("data-dir,d", bpo::value()->default_value("witness_node_data_dir"), + "Directory containing databases, configuration file, etc.") + ("version,v", "Display version information") + ("plugins", bpo::value() + ->default_value("witness account_history market_history grouped_orders api_helper_indexes"), + "Space-separated list of plugins to activate"); bpo::variables_map options; + bpo::options_description cli, cfg; + node->set_program_options(cli, cfg); + cfg_options.add(cfg); + + cfg_options.add_options() + ("plugins", bpo::value()->default_value("witness account_history market_history grouped_orders"), + "Space-separated list of plugins to activate"); + auto witness_plug = node->register_plugin(); auto history_plug = node->register_plugin(); auto market_history_plug = node->register_plugin(); @@ -95,6 +106,7 @@ int main(int argc, char** argv) { auto peerplays_sidechain = node->register_plugin(); // auto snapshot_plug = node->register_plugin(); + // add plugin options to config try { bpo::options_description cli, cfg; @@ -109,11 +121,6 @@ int main(int argc, char** argv) { return 1; } - if( options.count("help") ) - { - std::cout << app_options << "\n"; - return 0; - } if (options.count("version")) { std::string witness_version(graphene::utilities::git_revision_description); @@ -127,6 +134,11 @@ int main(int argc, char** argv) { std::cout << "Boost: " << boost::replace_all_copy(std::string(BOOST_LIB_VERSION), "_", ".") << "\n"; return 0; } + if( options.count("help") ) + { + std::cout << app_options << "\n"; + return 0; + } fc::path data_dir; if( options.count("data-dir") ) @@ -160,6 +172,7 @@ int main(int argc, char** argv) { if( !fc::exists(data_dir) ) fc::create_directories(data_dir); + boost::container::flat_set seen; std::ofstream out_cfg(config_ini_path.preferred_string()); for( const boost::shared_ptr od : cfg_options.options() ) { @@ -169,6 +182,9 @@ int main(int argc, char** argv) { if( !od->semantic()->apply_default(store) ) out_cfg << "# " << od->long_name() << " = \n"; else { + const std::string name = od->long_name(); + if( seen.find(name) != seen.end() ) continue; + seen.insert(name); auto example = od->format_parameter(); if( example.empty() ) // This is a boolean switch @@ -190,7 +206,22 @@ int main(int argc, char** argv) { fc::configure_logging(*logging_config); } + std::set plugins; + boost::split(plugins, options.at("plugins").as(), [](char c){return c == ' ';}); + + if(plugins.count("account_history") && plugins.count("elasticsearch")) { + std::cerr << "Plugin conflict: Cannot load both account_history plugin and elasticsearch plugin\n"; + return 1; + } + + std::for_each(plugins.begin(), plugins.end(), [node](const std::string& plug) mutable { + if (!plug.empty()) { + node->enable_plugin(plug); + } + }); + bpo::notify(options); + node->initialize(data_dir, options); node->initialize_plugins( options );