diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index b2b1bc89d8..20ef8d7bb7 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -61,6 +61,113 @@ namespace bpo = boost::program_options; void write_default_logging_config_to_stream(std::ostream& out); fc::optional load_logging_config_from_ini_file(const fc::path& config_ini_filename); +class deduplicator +{ + public: + deduplicator() : modifier(nullptr) {} + + deduplicator(const boost::shared_ptr (*mod_fn)(const boost::shared_ptr&)) + : modifier(mod_fn) {} + + const boost::shared_ptr next(const boost::shared_ptr& o) + { + const std::string name = o->long_name(); + if( seen.find( name ) != seen.end() ) + return nullptr; + seen.insert(name); + return modifier ? modifier(o) : o; + } + + private: + boost::container::flat_set seen; + const boost::shared_ptr (*modifier)(const boost::shared_ptr&); +}; + +static void load_config_file( const fc::path& config_ini_path, const bpo::options_description& cfg_options, + bpo::variables_map& options ) +{ + deduplicator dedup; + bpo::options_description unique_options("Graphene Witness Node"); + for( const boost::shared_ptr opt : cfg_options.options() ) + { + const boost::shared_ptr od = dedup.next(opt); + if( !od ) continue; + unique_options.add( od ); + } + + // get the basic options + bpo::store(bpo::parse_config_file(config_ini_path.preferred_string().c_str(), + unique_options, true), options); + + // try to get logging options from the config file. + try + { + fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); + if (logging_config) + fc::configure_logging(*logging_config); + } + catch (const fc::exception&) + { + wlog("Error parsing logging config from config file ${config}, using default config", ("config", config_ini_path.preferred_string())); + } +} + +const boost::shared_ptr new_option_description( const std::string& name, const bpo::value_semantic* value, const std::string& description ) +{ + bpo::options_description helper(""); + helper.add_options()( name.c_str(), value, description.c_str() ); + return helper.options()[0]; +} + +static void create_new_config_file( const fc::path& config_ini_path, const fc::path& data_dir, + const bpo::options_description& cfg_options ) +{ + ilog("Writing new config file at ${path}", ("path", config_ini_path)); + if( !fc::exists(data_dir) ) + fc::create_directories(data_dir); + + auto modify_option_defaults = [](const boost::shared_ptr& o) -> const boost::shared_ptr { + const std::string& name = o->long_name(); + if( name == "partial-operations" ) + return new_option_description( name, bpo::value()->default_value(true), o->description() ); + if( name == "max-ops-per-account" ) + return new_option_description( name, bpo::value()->default_value(1000), o->description() ); + return o; + }; + deduplicator dedup(modify_option_defaults); + std::ofstream out_cfg(config_ini_path.preferred_string()); + for( const boost::shared_ptr opt : cfg_options.options() ) + { + const boost::shared_ptr od = dedup.next(opt); + if( !od ) continue; + + if( !od->description().empty() ) + out_cfg << "# " << od->description() << "\n"; + boost::any store; + if( !od->semantic()->apply_default(store) ) + out_cfg << "# " << od->long_name() << " = \n"; + else { + auto example = od->format_parameter(); + if( example.empty() ) + // This is a boolean switch + out_cfg << od->long_name() << " = " << "false\n"; + else { + // The string is formatted "arg (=)" + example.erase(0, 6); + example.erase(example.length()-1); + out_cfg << od->long_name() << " = " << example << "\n"; + } + } + out_cfg << "\n"; + } + write_default_logging_config_to_stream(out_cfg); + out_cfg.close(); + // read the default logging config we just wrote out to the file and start using it + fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); + if (logging_config) + fc::configure_logging(*logging_config); +} + int main(int argc, char** argv) { app::application* node = new app::application(); fc::oexception unhandled_exception; @@ -109,72 +216,9 @@ int main(int argc, char** argv) { } fc::path config_ini_path = data_dir / "config.ini"; - if( fc::exists(config_ini_path) ) - { - boost::container::flat_set seen; - bpo::options_description unique_options("Graphene Witness Node"); - for( const boost::shared_ptr od : cfg_options.options() ) - { - const std::string name = od->long_name(); - if( seen.find(name) != seen.end() ) continue; - seen.insert(name); - unique_options.add( od ); - } - - // get the basic options - bpo::store(bpo::parse_config_file(config_ini_path.preferred_string().c_str(), unique_options, true), options); - - // try to get logging options from the config file. - try - { - fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); - if (logging_config) - fc::configure_logging(*logging_config); - } - catch (const fc::exception&) - { - wlog("Error parsing logging config from config file ${config}, using default config", ("config", config_ini_path.preferred_string())); - } - } - else - { - ilog("Writing new config file at ${path}", ("path", config_ini_path)); - 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() ) - { - if( !od->description().empty() ) - out_cfg << "# " << od->description() << "\n"; - boost::any store; - 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 - out_cfg << od->long_name() << " = " << "false\n"; - else { - // The string is formatted "arg (=)" - example.erase(0, 6); - example.erase(example.length()-1); - out_cfg << od->long_name() << " = " << example << "\n"; - } - } - out_cfg << "\n"; - } - write_default_logging_config_to_stream(out_cfg); - out_cfg.close(); - // read the default logging config we just wrote out to the file and start using it - fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); - if (logging_config) - fc::configure_logging(*logging_config); - } + if( !fc::exists(config_ini_path) ) + create_new_config_file( config_ini_path, data_dir, cfg_options ); + load_config_file( config_ini_path, cfg_options, options ); bpo::notify(options); node->initialize(data_dir, options);