Error type and config handling (#1416)
* Error type and config handling * Prevent splash screen from obscuring error dialog * Remove unnecessary string conversions * Add missing include * msvc barks at inline constexpr (N3652) * Remove unnecessary inline specifier * Incorporate review feedback * Remove superfluous inline keywords, fix size->empty * Use any_of instead of raw loop * Simplify file/stream handling and tests * Missing header * Explicit conversion operators, defaulted c'tors
This commit is contained in:
parent
79e6756151
commit
282cc0ddd3
23 changed files with 1420 additions and 687 deletions
|
|
@ -1,5 +1,6 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
#include <nano/node/working.hpp>
|
||||
|
||||
|
|
@ -428,7 +429,7 @@ TEST (logging, serialization)
|
|||
logging1.work_generation_time_value = !logging1.work_generation_time_value;
|
||||
logging1.log_to_cerr_value = !logging1.log_to_cerr_value;
|
||||
logging1.max_size = 10;
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
logging1.serialize_json (tree);
|
||||
nano::logging logging2;
|
||||
logging2.init (path);
|
||||
|
|
@ -460,7 +461,7 @@ TEST (logging, upgrade_v1_v2)
|
|||
logging1.init (path1);
|
||||
nano::logging logging2;
|
||||
logging2.init (path2);
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
logging1.serialize_json (tree);
|
||||
tree.erase ("version");
|
||||
tree.erase ("vote");
|
||||
|
|
@ -499,7 +500,7 @@ TEST (node_config, serialization)
|
|||
config1.callback_port = 10;
|
||||
config1.callback_target = "test";
|
||||
config1.lmdb_max_dbs = 256;
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
config1.serialize_json (tree);
|
||||
nano::logging logging2;
|
||||
logging2.init (path);
|
||||
|
|
@ -541,27 +542,27 @@ TEST (node_config, v1_v2_upgrade)
|
|||
auto path (nano::unique_path ());
|
||||
nano::logging logging1;
|
||||
logging1.init (path);
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
tree.put ("peering_port", std::to_string (0));
|
||||
tree.put ("packet_delay_microseconds", std::to_string (0));
|
||||
tree.put ("bootstrap_fraction_numerator", std::to_string (0));
|
||||
tree.put ("creation_rebroadcast", std::to_string (0));
|
||||
tree.put ("rebroadcast_delay", std::to_string (0));
|
||||
tree.put ("receive_minimum", nano::amount (0).to_string_dec ());
|
||||
boost::property_tree::ptree logging_l;
|
||||
nano::jsonconfig logging_l;
|
||||
logging1.serialize_json (logging_l);
|
||||
tree.add_child ("logging", logging_l);
|
||||
boost::property_tree::ptree preconfigured_peers_l;
|
||||
tree.add_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
boost::property_tree::ptree preconfigured_representatives_l;
|
||||
tree.add_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
tree.put_child ("logging", logging_l);
|
||||
nano::jsonconfig preconfigured_peers_l;
|
||||
tree.put_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
nano::jsonconfig preconfigured_representatives_l;
|
||||
tree.put_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
bool upgraded (false);
|
||||
nano::node_config config1;
|
||||
config1.logging.init (path);
|
||||
ASSERT_FALSE (tree.get_child_optional ("work_peers"));
|
||||
ASSERT_FALSE (tree.get_optional_child ("work_peers"));
|
||||
config1.deserialize_json (upgraded, tree);
|
||||
ASSERT_TRUE (upgraded);
|
||||
ASSERT_TRUE (!!tree.get_child_optional ("work_peers"));
|
||||
ASSERT_TRUE (!!tree.get_optional_child ("work_peers"));
|
||||
}
|
||||
|
||||
TEST (node_config, v2_v3_upgrade)
|
||||
|
|
@ -569,7 +570,7 @@ TEST (node_config, v2_v3_upgrade)
|
|||
auto path (nano::unique_path ());
|
||||
nano::logging logging1;
|
||||
logging1.init (path);
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
tree.put ("peering_port", std::to_string (0));
|
||||
tree.put ("packet_delay_microseconds", std::to_string (0));
|
||||
tree.put ("bootstrap_fraction_numerator", std::to_string (0));
|
||||
|
|
@ -577,18 +578,16 @@ TEST (node_config, v2_v3_upgrade)
|
|||
tree.put ("rebroadcast_delay", std::to_string (0));
|
||||
tree.put ("receive_minimum", nano::amount (0).to_string_dec ());
|
||||
tree.put ("version", "2");
|
||||
boost::property_tree::ptree logging_l;
|
||||
nano::jsonconfig logging_l;
|
||||
logging1.serialize_json (logging_l);
|
||||
tree.add_child ("logging", logging_l);
|
||||
boost::property_tree::ptree preconfigured_peers_l;
|
||||
tree.add_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
boost::property_tree::ptree preconfigured_representatives_l;
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("", "TR6ZJ4pdp6HC76xMRpVDny5x2s8AEbrhFue3NKVxYYdmKuTEib");
|
||||
preconfigured_representatives_l.push_back (std::make_pair ("", entry));
|
||||
tree.add_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
boost::property_tree::ptree work_peers_l;
|
||||
tree.add_child ("work_peers", work_peers_l);
|
||||
tree.put_child ("logging", logging_l);
|
||||
nano::jsonconfig preconfigured_peers_l;
|
||||
tree.put_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
nano::jsonconfig preconfigured_representatives_l;
|
||||
preconfigured_representatives_l.push ("TR6ZJ4pdp6HC76xMRpVDny5x2s8AEbrhFue3NKVxYYdmKuTEib");
|
||||
tree.put_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
nano::jsonconfig work_peers_l;
|
||||
tree.put_child ("work_peers", work_peers_l);
|
||||
bool upgraded (false);
|
||||
nano::node_config config1;
|
||||
config1.logging.init (path);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <nano/core_test/testutil.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/common.hpp>
|
||||
#include <nano/node/rpc.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
|
@ -1578,7 +1579,7 @@ TEST (rpc_config, serialization)
|
|||
config1.enable_control = true;
|
||||
config1.frontier_request_limit = 8192;
|
||||
config1.chain_request_limit = 4096;
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
config1.serialize_json (tree);
|
||||
nano::rpc_config config2;
|
||||
ASSERT_NE (config2.address, config1.address);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <nano/lib/interface.h>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
|
||||
namespace
|
||||
|
|
@ -427,24 +428,38 @@ TEST (uint256_union, operator_less_than)
|
|||
test_union_operator_less_than<nano::uint256_union, nano::uint256_t> ();
|
||||
}
|
||||
|
||||
class json_initial_value_test
|
||||
{
|
||||
public:
|
||||
json_initial_value_test (std::string text_a) :
|
||||
text (std::move (text_a))
|
||||
{
|
||||
}
|
||||
nano::error serialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
json.put ("thing", text);
|
||||
return json.get_error ();
|
||||
}
|
||||
std::string text;
|
||||
};
|
||||
|
||||
class json_upgrade_test
|
||||
{
|
||||
public:
|
||||
bool deserialize_json (bool & upgraded, boost::property_tree::ptree & tree_a)
|
||||
nano::error deserialize_json (bool & upgraded, nano::jsonconfig & json)
|
||||
{
|
||||
auto error (false);
|
||||
if (!tree_a.empty ())
|
||||
if (!json.empty ())
|
||||
{
|
||||
auto text_l (tree_a.get<std::string> ("thing"));
|
||||
if (text_l == "junktest")
|
||||
auto text_l (json.get<std::string> ("thing"));
|
||||
if (text_l == "junktest" || text_l == "created")
|
||||
{
|
||||
upgraded = true;
|
||||
text_l = "changed";
|
||||
tree_a.put ("thing", text_l);
|
||||
json.put ("thing", text_l);
|
||||
}
|
||||
if (text_l == "error")
|
||||
{
|
||||
error = true;
|
||||
json.get_error () = nano::error_common::generic;
|
||||
}
|
||||
text = text_l;
|
||||
}
|
||||
|
|
@ -452,63 +467,41 @@ public:
|
|||
{
|
||||
upgraded = true;
|
||||
text = "created";
|
||||
tree_a.put ("thing", text);
|
||||
json.put ("thing", text);
|
||||
}
|
||||
return error;
|
||||
return json.get_error ();
|
||||
}
|
||||
std::string text;
|
||||
};
|
||||
|
||||
TEST (json, fetch_object)
|
||||
/** Both create and upgrade via read_and_update() */
|
||||
TEST (json, create_and_upgrade)
|
||||
{
|
||||
auto path1 (nano::unique_path ());
|
||||
std::fstream stream1;
|
||||
nano::open_or_create (stream1, path1.string ());
|
||||
stream1 << "{ \"thing\": \"junktest\" }";
|
||||
stream1.close ();
|
||||
nano::open_or_create (stream1, path1.string ());
|
||||
auto path (nano::unique_path ());
|
||||
nano::jsonconfig json;
|
||||
json_upgrade_test object1;
|
||||
auto error1 (nano::fetch_object (object1, path1));
|
||||
ASSERT_FALSE (error1);
|
||||
ASSERT_EQ ("changed", object1.text);
|
||||
boost::property_tree::ptree tree1;
|
||||
stream1.close ();
|
||||
nano::open_or_create (stream1, path1.string ());
|
||||
boost::property_tree::read_json (stream1, tree1);
|
||||
ASSERT_EQ ("changed", tree1.get<std::string> ("thing"));
|
||||
std::string string2 ("{ \"thing\": \"junktest2\" }");
|
||||
std::stringstream stream2 (string2);
|
||||
ASSERT_FALSE (json.read_and_update (object1, path));
|
||||
ASSERT_EQ ("created", object1.text);
|
||||
|
||||
nano::jsonconfig json2;
|
||||
json_upgrade_test object2;
|
||||
auto error2 (nano::fetch_object (object2, stream2));
|
||||
ASSERT_FALSE (error2);
|
||||
ASSERT_EQ ("junktest2", object2.text);
|
||||
ASSERT_EQ ("{ \"thing\": \"junktest2\" }", string2);
|
||||
std::string string3 ("{ \"thing\": \"error\" }");
|
||||
std::stringstream stream3 (string3);
|
||||
json_upgrade_test object3;
|
||||
auto error3 (nano::fetch_object (object3, stream3));
|
||||
ASSERT_TRUE (error3);
|
||||
auto path2 (nano::unique_path ());
|
||||
std::fstream stream4;
|
||||
nano::open_or_create (stream4, path2.string ());
|
||||
json_upgrade_test object4;
|
||||
auto error4 (nano::fetch_object (object4, path2));
|
||||
ASSERT_FALSE (error4);
|
||||
ASSERT_EQ ("created", object4.text);
|
||||
boost::property_tree::ptree tree2;
|
||||
stream4.close ();
|
||||
nano::open_or_create (stream4, path2.string ());
|
||||
boost::property_tree::read_json (stream4, tree2);
|
||||
ASSERT_EQ ("created", tree2.get<std::string> ("thing"));
|
||||
ASSERT_FALSE (json2.read_and_update (object2, path));
|
||||
ASSERT_EQ ("changed", object2.text);
|
||||
}
|
||||
|
||||
TEST (json, DISABLED_fetch_write_fail)
|
||||
/** Create config manually, then upgrade via read_and_update() with multiple calls to test idempotence */
|
||||
TEST (json, upgrade_from_existing)
|
||||
{
|
||||
std::string string4 ("");
|
||||
std::stringstream stream4 (string4, std::ios_base::in);
|
||||
json_upgrade_test object4;
|
||||
auto error4 (nano::fetch_object (object4, stream4));
|
||||
ASSERT_TRUE (error4);
|
||||
auto path (nano::unique_path ());
|
||||
nano::jsonconfig json;
|
||||
json_initial_value_test junktest ("junktest");
|
||||
junktest.serialize_json (json);
|
||||
json.write (path);
|
||||
json_upgrade_test object1;
|
||||
ASSERT_FALSE (json.read_and_update (object1, path));
|
||||
ASSERT_EQ ("changed", object1.text);
|
||||
ASSERT_FALSE (json.read_and_update (object1, path));
|
||||
ASSERT_EQ ("changed", object1.text);
|
||||
}
|
||||
|
||||
TEST (uint64_t, parse)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/wallet.hpp>
|
||||
|
||||
|
|
@ -88,7 +89,7 @@ TEST (work, opencl_config)
|
|||
config1.platform = 1;
|
||||
config1.device = 2;
|
||||
config1.threads = 3;
|
||||
boost::property_tree::ptree tree;
|
||||
nano::jsonconfig tree;
|
||||
config1.serialize_json (tree);
|
||||
nano::opencl_config config2;
|
||||
ASSERT_FALSE (config2.deserialize_json (tree));
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ add_library (nano_lib
|
|||
config.hpp
|
||||
interface.cpp
|
||||
interface.h
|
||||
jsonconfig.hpp
|
||||
numbers.cpp
|
||||
numbers.hpp
|
||||
timer.hpp
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ std::string nano::error_common_messages::message (int ev) const
|
|||
return "Missing signature";
|
||||
case nano::error_common::missing_work:
|
||||
return "Missing work";
|
||||
case nano::error_common::exception:
|
||||
return "Exception thrown";
|
||||
case nano::error_common::account_exists:
|
||||
return "Account already exists";
|
||||
case nano::error_common::account_not_found:
|
||||
|
|
@ -66,6 +68,8 @@ std::string nano::error_common_messages::message (int ev) const
|
|||
return "Invalid port";
|
||||
case nano::error_common::invalid_index:
|
||||
return "Invalid index";
|
||||
case nano::error_common::invalid_type_conversion:
|
||||
return "Invalid type conversion";
|
||||
case nano::error_common::invalid_work:
|
||||
return "Invalid work";
|
||||
case nano::error_common::numeric_conversion:
|
||||
|
|
@ -199,3 +203,18 @@ std::string nano::error_process_messages::message (int ev) const
|
|||
|
||||
return "Invalid error code";
|
||||
}
|
||||
|
||||
std::string nano::error_config_messages::message (int ev) const
|
||||
{
|
||||
switch (static_cast<nano::error_config> (ev))
|
||||
{
|
||||
case nano::error_config::generic:
|
||||
return "Unknown error";
|
||||
case nano::error_config::invalid_value:
|
||||
return "Invalid configuration value";
|
||||
case nano::error_config::missing_value:
|
||||
return "Missing value in configuration";
|
||||
}
|
||||
|
||||
return "Invalid error code";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <memory>
|
||||
#include <nano/lib/expected.hpp>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
|
@ -10,24 +13,11 @@ using tl::make_unexpected;
|
|||
|
||||
namespace nano
|
||||
{
|
||||
/** Returns the error code if non-zero, otherwise the value */
|
||||
template <class T>
|
||||
auto either (T && value, std::error_code ec) -> expected<typename std::remove_reference<T>::type, std::error_code>
|
||||
{
|
||||
if (ec)
|
||||
{
|
||||
return make_unexpected (ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::move (value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Common error codes */
|
||||
enum class error_common
|
||||
{
|
||||
generic = 1,
|
||||
exception,
|
||||
account_not_found,
|
||||
account_not_found_wallet,
|
||||
account_exists,
|
||||
|
|
@ -57,6 +47,7 @@ enum class error_common
|
|||
invalid_index,
|
||||
invalid_ip_address,
|
||||
invalid_port,
|
||||
invalid_type_conversion,
|
||||
invalid_work,
|
||||
insufficient_balance,
|
||||
numeric_conversion,
|
||||
|
|
@ -125,6 +116,29 @@ enum class error_process
|
|||
block_position, // This block cannot follow the previous block
|
||||
other
|
||||
};
|
||||
|
||||
/** config.json deserialization related errors */
|
||||
enum class error_config
|
||||
{
|
||||
generic = 1,
|
||||
invalid_value,
|
||||
missing_value,
|
||||
};
|
||||
|
||||
} // nano namespace
|
||||
|
||||
/** Returns the error code if non-zero, otherwise the value */
|
||||
template <class T>
|
||||
auto either (T && value, std::error_code ec) -> expected<typename std::remove_reference_t<T>, std::error_code>
|
||||
{
|
||||
if (ec)
|
||||
{
|
||||
return make_unexpected (ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::move (value);
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience macro to implement the standard boilerplate for using std::error_code with enums
|
||||
|
|
@ -172,3 +186,290 @@ REGISTER_ERROR_CODES (nano, error_common);
|
|||
REGISTER_ERROR_CODES (nano, error_blocks);
|
||||
REGISTER_ERROR_CODES (nano, error_rpc);
|
||||
REGISTER_ERROR_CODES (nano, error_process);
|
||||
REGISTER_ERROR_CODES (nano, error_config);
|
||||
|
||||
/* boost->std error_code bridge */
|
||||
namespace nano
|
||||
{
|
||||
namespace error_conversion
|
||||
{
|
||||
const std::error_category & generic_category ();
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct is_error_code_enum<boost::system::errc::errc_t>
|
||||
: public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
inline std::error_code make_error_code (boost::system::errc::errc_t e)
|
||||
{
|
||||
return std::error_code (static_cast<int> (e),
|
||||
::nano::error_conversion::generic_category ());
|
||||
}
|
||||
}
|
||||
namespace nano
|
||||
{
|
||||
namespace error_conversion
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class generic_category : public std::error_category
|
||||
{
|
||||
public:
|
||||
virtual const char * name () const noexcept override
|
||||
{
|
||||
return boost::system::generic_category ().name ();
|
||||
}
|
||||
virtual std::string message (int value) const override
|
||||
{
|
||||
return boost::system::generic_category ().message (value);
|
||||
}
|
||||
};
|
||||
}
|
||||
inline const std::error_category & generic_category ()
|
||||
{
|
||||
static detail::generic_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline std::error_code convert (const boost::system::error_code & error)
|
||||
{
|
||||
if (error.category () == boost::system::generic_category ())
|
||||
{
|
||||
return std::error_code (error.value (),
|
||||
nano::error_conversion::generic_category ());
|
||||
}
|
||||
assert (false);
|
||||
|
||||
return nano::error_common::invalid_type_conversion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/** Adapter for std/boost::error_code, std::exception and bool flags to facilitate unified error handling */
|
||||
class error
|
||||
{
|
||||
public:
|
||||
error () = default;
|
||||
error (nano::error const & error_a) = default;
|
||||
error (nano::error && error_a) = default;
|
||||
|
||||
error (std::error_code code_a)
|
||||
{
|
||||
code = code_a;
|
||||
}
|
||||
|
||||
error (std::string message_a)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
message = std::move (message_a);
|
||||
}
|
||||
|
||||
error (std::exception const & exception_a)
|
||||
{
|
||||
code = nano::error_common::exception;
|
||||
message = exception_a.what ();
|
||||
}
|
||||
|
||||
error & operator= (nano::error const & err_a)
|
||||
{
|
||||
code = err_a.code;
|
||||
message = err_a.message;
|
||||
return *this;
|
||||
}
|
||||
|
||||
error & operator= (nano::error && err_a)
|
||||
{
|
||||
code = err_a.code;
|
||||
message = std::move (err_a.message);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign error code */
|
||||
error & operator= (const std::error_code code_a)
|
||||
{
|
||||
code = code_a;
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign boost error code (as converted to std::error_code) */
|
||||
error & operator= (const boost::system::error_code & code_a)
|
||||
{
|
||||
code = nano::error_conversion::convert (code_a);
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Assign boost error code (as converted to std::error_code) */
|
||||
error & operator= (const boost::system::errc::errc_t & code_a)
|
||||
{
|
||||
code = nano::error_conversion::convert (boost::system::errc::make_error_code (code_a));
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set the error to nano::error_common::generic and the error message to \p message_a */
|
||||
error & operator= (const std::string message_a)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
message = std::move (message_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set the error to nano::error_common::generic. */
|
||||
error & operator= (bool is_error)
|
||||
{
|
||||
if (is_error)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
}
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Sets the error to nano::error_common::exception and adopts the exception error message. */
|
||||
error & operator= (std::exception const & exception_a)
|
||||
{
|
||||
code = nano::error_common::exception;
|
||||
message = exception_a.what ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return true if this#error_code equals the parameter */
|
||||
bool operator== (const std::error_code code_a)
|
||||
{
|
||||
return code == code_a;
|
||||
}
|
||||
|
||||
/** Return true if this#error_code equals the parameter */
|
||||
bool operator== (const boost::system::error_code code_a)
|
||||
{
|
||||
return code.value () == code_a.value ();
|
||||
}
|
||||
|
||||
/** Call the function iff the current error is zero */
|
||||
error & then (std::function<nano::error &()> next)
|
||||
{
|
||||
return code ? *this : next ();
|
||||
}
|
||||
|
||||
/** If the current error is one of the listed codes, reset the error code */
|
||||
template <typename... ErrorCode>
|
||||
error & accept (ErrorCode... err)
|
||||
{
|
||||
// Convert variadic arguments to std::error_code
|
||||
auto codes = { std::error_code (err)... };
|
||||
if (std::any_of (codes.begin (), codes.end (), [this, &codes](auto & code_a) { return code == code_a; }))
|
||||
{
|
||||
code.clear ();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Implicit error_code conversion */
|
||||
explicit operator std::error_code () const
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
/** Implicit bool conversion; true if there's an error */
|
||||
explicit operator bool () const
|
||||
{
|
||||
return code.value () != 0;
|
||||
}
|
||||
|
||||
/** Implicit string conversion; returns the error message or an empty string. */
|
||||
explicit operator std::string () const
|
||||
{
|
||||
return get_message ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error message, or an empty string if there's no error. If a custom error message is set,
|
||||
* that will be returned, otherwise the error_code#message() is returned.
|
||||
*/
|
||||
std::string get_message () const
|
||||
{
|
||||
std::string res = message;
|
||||
if (code && res.empty ())
|
||||
{
|
||||
res = code.message ();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Set an error message, but only if the error code is already set */
|
||||
error & on_error (std::string message_a)
|
||||
{
|
||||
if (code)
|
||||
{
|
||||
message = std::move (message_a);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set an error message if the current error code matches \p code_a */
|
||||
error & on_error (std::error_code code_a, std::string message_a)
|
||||
{
|
||||
if (code == code_a)
|
||||
{
|
||||
message = std::move (message_a);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set an error message and an error code */
|
||||
error & set (std::string message_a, std::error_code code_a = nano::error_common::generic)
|
||||
{
|
||||
message = message_a;
|
||||
code = code_a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set a custom error message. If the error code is not set, it will be set to nano::error_common::generic. */
|
||||
error & set_message (std::string message_a)
|
||||
{
|
||||
if (!code)
|
||||
{
|
||||
code = nano::error_common::generic;
|
||||
}
|
||||
message = std::move (message_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Clear an errors */
|
||||
error & clear ()
|
||||
{
|
||||
code.clear ();
|
||||
message.clear ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::error_code code;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
/**
|
||||
* A type that manages a nano::error.
|
||||
* The default return type is nano::error&, though shared_ptr<nano::error> is a good option in cases
|
||||
* where shared error state is desirable.
|
||||
*/
|
||||
template <typename RET_TYPE = nano::error &>
|
||||
class error_aware
|
||||
{
|
||||
static_assert (std::is_same<RET_TYPE, nano::error &>::value || std::is_same<RET_TYPE, std::shared_ptr<nano::error>>::value, "Must be nano::error& or shared_ptr<nano::error>");
|
||||
|
||||
public:
|
||||
/** Returns the error object managed by this object */
|
||||
virtual RET_TYPE get_error () = 0;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
487
nano/lib/jsonconfig.hpp
Normal file
487
nano/lib/jsonconfig.hpp
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <fstream>
|
||||
#include <nano/lib/errors.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/** Type trait to determine if T is compatible with boost's lexical_cast */
|
||||
template <class T>
|
||||
struct is_lexical_castable : std::integral_constant<bool,
|
||||
(std::is_default_constructible<T>::value && (boost::has_right_shift<std::basic_istream<wchar_t>, T>::value || boost::has_right_shift<std::basic_istream<char>, T>::value))>
|
||||
{
|
||||
};
|
||||
|
||||
/* Type descriptions are used to automatically construct configuration error messages */
|
||||
// clang-format off
|
||||
template <typename T> inline std::string type_desc (void) { return "an unknown type"; }
|
||||
template <> inline std::string type_desc<int8_t> (void) { return "an integer between -128 and 127"; }
|
||||
template <> inline std::string type_desc<uint8_t> (void) { return "an integer between 0 and 255"; }
|
||||
template <> inline std::string type_desc<int16_t> (void) { return "an integer between -32768 and 32767"; }
|
||||
template <> inline std::string type_desc<uint16_t> (void) { return "an integer between 0 and 65535"; }
|
||||
template <> inline std::string type_desc<int32_t> (void) { return "a 32-bit signed integer"; }
|
||||
template <> inline std::string type_desc<uint32_t> (void) { return "a 32-bit unsigned integer"; }
|
||||
template <> inline std::string type_desc<int64_t> (void) { return "a 64-bit signed integer"; }
|
||||
template <> inline std::string type_desc<uint64_t> (void) { return "a 64-bit unsigned integer"; }
|
||||
template <> inline std::string type_desc<float> (void) { return "a single precision floating point number"; }
|
||||
template <> inline std::string type_desc<double> (void) { return "a double precison floating point number"; }
|
||||
template <> inline std::string type_desc<char> (void) { return "a character"; }
|
||||
template <> inline std::string type_desc<std::string> (void) { return "a string"; }
|
||||
template <> inline std::string type_desc<bool> (void) { return "a boolean"; }
|
||||
template <> inline std::string type_desc<boost::asio::ip::address_v6> (void) { return "an IP address"; }
|
||||
// clang-format on
|
||||
|
||||
/** Manages a node in a boost configuration tree. */
|
||||
class jsonconfig : public nano::error_aware<>
|
||||
{
|
||||
public:
|
||||
jsonconfig ()
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
|
||||
jsonconfig (boost::property_tree::ptree const & tree_a, std::shared_ptr<nano::error> error_a = nullptr) :
|
||||
tree (tree_a), error (error_a)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
error = std::make_shared<nano::error> ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a json object from the stream and if it was changed, write the object back to the stream.
|
||||
* @return nano::error&, including a descriptive error message if the config file is malformed.
|
||||
*/
|
||||
template <typename T>
|
||||
nano::error & read_and_update (T & object, boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
if (!stream.fail ())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_json (stream, tree);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
auto pos (stream.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
*error = ex;
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
if (!*error)
|
||||
{
|
||||
auto updated (false);
|
||||
*error = object.deserialize_json (updated, *this);
|
||||
if (!*error && updated)
|
||||
{
|
||||
stream.open (path_a.string (), std::ios_base::out | std::ios_base::trunc);
|
||||
try
|
||||
{
|
||||
boost::property_tree::write_json (stream, tree);
|
||||
}
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
*error = ex;
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
}
|
||||
}
|
||||
return *error;
|
||||
}
|
||||
|
||||
void write (boost::filesystem::path const & path_a)
|
||||
{
|
||||
std::fstream stream;
|
||||
open_or_create (stream, path_a.string ());
|
||||
write (stream);
|
||||
}
|
||||
|
||||
void write (std::ostream & stream_a) const
|
||||
{
|
||||
boost::property_tree::write_json (stream_a, tree);
|
||||
}
|
||||
|
||||
void read (std::istream & stream_a)
|
||||
{
|
||||
boost::property_tree::read_json (stream_a, tree);
|
||||
}
|
||||
|
||||
/** Open confiruation file, create if necessary */
|
||||
void open_or_create (std::fstream & stream_a, std::string const & path_a)
|
||||
{
|
||||
stream_a.open (path_a, std::ios_base::in);
|
||||
if (stream_a.fail ())
|
||||
{
|
||||
stream_a.open (path_a, std::ios_base::out);
|
||||
}
|
||||
stream_a.close ();
|
||||
stream_a.open (path_a, std::ios_base::in | std::ios_base::out);
|
||||
}
|
||||
|
||||
/** Returns the boost property node managed by this instance */
|
||||
boost::property_tree::ptree const & get_tree ()
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
/** Returns true if the property tree node is empty */
|
||||
bool empty () const
|
||||
{
|
||||
return tree.empty ();
|
||||
}
|
||||
|
||||
/** Optionally returns the given child node */
|
||||
jsonconfig & get_optional_child (std::string const & key_a, boost::optional<jsonconfig> & child_config)
|
||||
{
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (child)
|
||||
{
|
||||
child_config = jsonconfig (child.get (), error);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
boost::optional<jsonconfig> get_optional_child (std::string const & key_a)
|
||||
{
|
||||
boost::optional<jsonconfig> child_config;
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (child)
|
||||
{
|
||||
child_config = jsonconfig (child.get (), error);
|
||||
}
|
||||
return child_config;
|
||||
}
|
||||
|
||||
jsonconfig & get_required_child (std::string const & key_a, jsonconfig & child_config /*out*/)
|
||||
{
|
||||
auto child = tree.get_child_optional (key_a);
|
||||
if (child)
|
||||
{
|
||||
child_config = jsonconfig (child.get (), error);
|
||||
}
|
||||
else if (!*error)
|
||||
{
|
||||
*error = nano::error_config::missing_value;
|
||||
error->set_message ("Missing configuration node: " + key_a);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
jsonconfig get_required_child (std::string const & key_a)
|
||||
{
|
||||
jsonconfig child_config;
|
||||
get_required_child (key_a, child_config);
|
||||
return child_config;
|
||||
}
|
||||
|
||||
jsonconfig & put_child (std::string const & key_a, nano::jsonconfig & conf_a)
|
||||
{
|
||||
tree.add_child (key_a, conf_a.get_tree ());
|
||||
return *this;
|
||||
}
|
||||
|
||||
jsonconfig & replace_child (std::string const & key_a, nano::jsonconfig & conf_a)
|
||||
{
|
||||
conf_a.erase (key_a);
|
||||
conf_a.put_child (key_a, conf_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Set value for the given key. Any existing value will be overwritten. */
|
||||
template <typename T>
|
||||
jsonconfig & put (std::string const & key, T const & value)
|
||||
{
|
||||
tree.put (key, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Push array element */
|
||||
template <typename T>
|
||||
jsonconfig & push (T const & value)
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("", value);
|
||||
tree.push_back (std::make_pair ("", entry));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Iterate array entries */
|
||||
template <typename T>
|
||||
jsonconfig & array_entries (std::function<void(T)> callback)
|
||||
{
|
||||
for (auto & entry : tree)
|
||||
{
|
||||
callback (entry.second.get<T> (""));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if \p key_a is present */
|
||||
bool has_key (std::string const & key_a)
|
||||
{
|
||||
return tree.find (key_a) != tree.not_found ();
|
||||
}
|
||||
|
||||
/** Erase the property of given key */
|
||||
jsonconfig & erase (std::string const & key_a)
|
||||
{
|
||||
tree.erase (key_a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Get optional, using \p default_value if \p key is missing. */
|
||||
template <typename T>
|
||||
jsonconfig & get_optional (std::string const & key, T & target, T default_value)
|
||||
{
|
||||
get_config<T> (true, key, target, default_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get optional value, using the current value of \p target as the default if \p key is missing.
|
||||
* @return May return nano::error_config::invalid_value
|
||||
*/
|
||||
template <typename T>
|
||||
jsonconfig & get_optional (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (true, key, target, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return a boost::optional<T> for the given key */
|
||||
template <typename T>
|
||||
boost::optional<T> get_optional (std::string const & key)
|
||||
{
|
||||
boost::optional<T> res;
|
||||
if (has_key (key))
|
||||
{
|
||||
T target{};
|
||||
get_config<T> (true, key, target, target);
|
||||
res = target;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Get value, using the current value of \p target as the default if \p key is missing. */
|
||||
template <typename T>
|
||||
jsonconfig & get (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (true, key, target, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of required key
|
||||
* @note May set nano::error_config::missing_value if \p key is missing, nano::error_config::invalid_value if value is invalid.
|
||||
*/
|
||||
template <typename T>
|
||||
T get (std::string const & key)
|
||||
{
|
||||
T target{};
|
||||
get_config<T> (true, key, target, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get required value.
|
||||
* @note May set nano::error_config::missing_value if \p key is missing, nano::error_config::invalid_value if value is invalid.
|
||||
*/
|
||||
template <typename T>
|
||||
jsonconfig & get_required (std::string const & key, T & target)
|
||||
{
|
||||
get_config<T> (false, key, target);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Turn on or off automatic error message generation */
|
||||
void set_auto_error_message (bool auto_a)
|
||||
{
|
||||
auto_error_message = auto_a;
|
||||
}
|
||||
|
||||
nano::error & get_error () override
|
||||
{
|
||||
return *error;
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
void construct_error_message (bool optional, std::string const & key)
|
||||
{
|
||||
if (auto_error_message && *error)
|
||||
{
|
||||
if (optional)
|
||||
{
|
||||
error->set_message (key + " is not " + type_desc<T> ());
|
||||
}
|
||||
else
|
||||
{
|
||||
error->set_message (key + " is required and must be " + type_desc<T> ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set error if not already set. That is, first error remains until get_error().clear() is called. */
|
||||
template <typename T, typename V>
|
||||
void conditionally_set_error (V error_a, bool optional, std::string const & key)
|
||||
{
|
||||
if (!*error)
|
||||
{
|
||||
*error = error_a;
|
||||
construct_error_message<T> (optional, key);
|
||||
}
|
||||
}
|
||||
template <typename T, typename = std::enable_if_t<nano::is_lexical_castable<T>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, T & target, T default_value = T ())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
if (!boost::conversion::try_lexical_convert<T> (val, target))
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const & ex)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// boost's lexical cast doesn't handle (u)int8_t
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, uint8_t>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, uint8_t & target, uint8_t default_value = T ())
|
||||
{
|
||||
int64_t tmp;
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
if (!boost::conversion::try_lexical_convert<int64_t> (val, tmp) || tmp < 0 || tmp > 255)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = static_cast<uint8_t> (tmp);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const & ex)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, bool>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, bool & target, bool default_value = false)
|
||||
{
|
||||
auto bool_conv = [this, &target, &key, optional](std::string val) {
|
||||
if (val == "true")
|
||||
{
|
||||
target = true;
|
||||
}
|
||||
else if (val == "false")
|
||||
{
|
||||
target = false;
|
||||
}
|
||||
else if (!*error)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
auto val (tree.get<std::string> (key));
|
||||
bool_conv (val);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const & ex)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error & ex)
|
||||
{
|
||||
conditionally_set_error<T> (ex, optional, key);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_same<T, boost::asio::ip::address_v6>::value>>
|
||||
jsonconfig & get_config (bool optional, std::string key, boost::asio::ip::address_v6 & target, boost::asio::ip::address_v6 default_value = T ())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto address_l (tree.get<std::string> (key));
|
||||
boost::system::error_code bec;
|
||||
target = boost::asio::ip::address_v6::from_string (address_l, bec);
|
||||
if (bec)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::invalid_value, optional, key);
|
||||
}
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path const & ex)
|
||||
{
|
||||
if (!optional)
|
||||
{
|
||||
conditionally_set_error<T> (nano::error_config::missing_value, optional, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
/** The property node being managed */
|
||||
boost::property_tree::ptree tree;
|
||||
|
||||
/** If set, automatically construct error messages based on parameters and type information. */
|
||||
bool auto_error_message{ true };
|
||||
|
||||
/** We're a nano::error_aware type. Child nodes share the error state. */
|
||||
std::shared_ptr<nano::error> error;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/nano_node/daemon.hpp>
|
||||
|
||||
|
|
@ -12,86 +13,104 @@ opencl_enable (false)
|
|||
{
|
||||
}
|
||||
|
||||
void nano_daemon::daemon_config::serialize_json (boost::property_tree::ptree & tree_a)
|
||||
nano::error nano_daemon::daemon_config::serialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
tree_a.put ("rpc_enable", rpc_enable);
|
||||
boost::property_tree::ptree rpc_l;
|
||||
json.put ("version", json_version ());
|
||||
json.put ("rpc_enable", rpc_enable);
|
||||
|
||||
nano::jsonconfig rpc_l;
|
||||
rpc.serialize_json (rpc_l);
|
||||
tree_a.add_child ("rpc", rpc_l);
|
||||
boost::property_tree::ptree node_l;
|
||||
json.put_child ("rpc", rpc_l);
|
||||
|
||||
nano::jsonconfig node_l;
|
||||
node.serialize_json (node_l);
|
||||
tree_a.add_child ("node", node_l);
|
||||
tree_a.put ("opencl_enable", opencl_enable);
|
||||
boost::property_tree::ptree opencl_l;
|
||||
nano::jsonconfig node (node_l);
|
||||
json.put_child ("node", node);
|
||||
|
||||
json.put ("opencl_enable", opencl_enable);
|
||||
nano::jsonconfig opencl_l;
|
||||
opencl.serialize_json (opencl_l);
|
||||
tree_a.add_child ("opencl", opencl_l);
|
||||
json.put_child ("opencl", opencl_l);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano_daemon::daemon_config::deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
|
||||
nano::error nano_daemon::daemon_config::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
|
||||
{
|
||||
auto error (false);
|
||||
try
|
||||
{
|
||||
if (!tree_a.empty ())
|
||||
if (!json.empty ())
|
||||
{
|
||||
auto version_l (tree_a.get_optional<std::string> ("version"));
|
||||
if (!version_l)
|
||||
int version_l;
|
||||
json.get_optional<int> ("version", version_l);
|
||||
upgraded_a |= upgrade_json (version_l, json);
|
||||
|
||||
json.get_optional<bool> ("rpc_enable", rpc_enable);
|
||||
nano::jsonconfig rpc_l;
|
||||
json.get_required_child ("rpc", rpc_l);
|
||||
|
||||
if (!rpc.deserialize_json (rpc_l))
|
||||
{
|
||||
tree_a.put ("version", "1");
|
||||
version_l = "1";
|
||||
nano::jsonconfig node_l;
|
||||
json.get_required_child ("node", node_l);
|
||||
if (!json.get_error ())
|
||||
{
|
||||
node.deserialize_json (upgraded_a, node_l);
|
||||
}
|
||||
}
|
||||
if (!json.get_error ())
|
||||
{
|
||||
json.get_required<bool> ("opencl_enable", opencl_enable);
|
||||
nano::jsonconfig opencl_l;
|
||||
json.get_required_child ("opencl", opencl_l);
|
||||
if (!json.get_error ())
|
||||
{
|
||||
opencl.deserialize_json (opencl_l);
|
||||
}
|
||||
}
|
||||
upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
|
||||
rpc_enable = tree_a.get<bool> ("rpc_enable");
|
||||
auto rpc_l (tree_a.get_child ("rpc"));
|
||||
error |= rpc.deserialize_json (rpc_l);
|
||||
auto & node_l (tree_a.get_child ("node"));
|
||||
error |= node.deserialize_json (upgraded_a, node_l);
|
||||
opencl_enable = tree_a.get<bool> ("opencl_enable");
|
||||
auto & opencl_l (tree_a.get_child ("opencl"));
|
||||
error |= opencl.deserialize_json (opencl_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
upgraded_a = true;
|
||||
serialize_json (tree_a);
|
||||
serialize_json (json);
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
error = true;
|
||||
json.get_error () = ex;
|
||||
}
|
||||
return error;
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano_daemon::daemon_config::upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
|
||||
bool nano_daemon::daemon_config::upgrade_json (unsigned version_a, nano::jsonconfig & json)
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
auto result (false);
|
||||
json.put ("version", json_version ());
|
||||
auto upgraded_l (false);
|
||||
switch (version_a)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
auto opencl_enable_l (tree_a.get_optional<bool> ("opencl_enable"));
|
||||
bool opencl_enable_l;
|
||||
json.get_optional<bool> ("opencl_enable", opencl_enable_l);
|
||||
if (!opencl_enable_l)
|
||||
{
|
||||
tree_a.put ("opencl_enable", "false");
|
||||
json.put ("opencl_enable", false);
|
||||
}
|
||||
auto opencl_l (tree_a.get_child_optional ("opencl"));
|
||||
boost::optional<nano::jsonconfig> opencl_l;
|
||||
json.get_optional_child ("opencl", opencl_l);
|
||||
if (!opencl_l)
|
||||
{
|
||||
boost::property_tree::ptree opencl_l;
|
||||
nano::jsonconfig opencl_l;
|
||||
opencl.serialize_json (opencl_l);
|
||||
tree_a.put_child ("opencl", opencl_l);
|
||||
json.put_child ("opencl", opencl_l);
|
||||
}
|
||||
result = true;
|
||||
upgraded_l = true;
|
||||
}
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error ("Unknown daemon_config version");
|
||||
}
|
||||
return result;
|
||||
return upgraded_l;
|
||||
}
|
||||
|
||||
void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::node_flags const & flags)
|
||||
|
|
@ -102,7 +121,8 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
|
|||
nano::set_secure_perm_directory (data_path, error_chmod);
|
||||
auto config_path ((data_path / "config.json"));
|
||||
std::unique_ptr<nano::thread_runner> runner;
|
||||
auto error (nano::fetch_object (config, config_path));
|
||||
nano::jsonconfig json;
|
||||
auto error (json.read_and_update (config, config_path));
|
||||
nano::set_secure_perm_file (config_path, error_chmod);
|
||||
if (!error)
|
||||
{
|
||||
|
|
@ -142,6 +162,6 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
|
|||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error deserializing config\n";
|
||||
std::cerr << "Error deserializing config: " << error.get_message () << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/rpc.hpp>
|
||||
|
||||
|
|
@ -12,14 +13,22 @@ class daemon_config
|
|||
{
|
||||
public:
|
||||
daemon_config ();
|
||||
bool deserialize_json (bool &, boost::property_tree::ptree &);
|
||||
void serialize_json (boost::property_tree::ptree &);
|
||||
bool upgrade_json (unsigned, boost::property_tree::ptree &);
|
||||
nano::error deserialize_json (bool &, nano::jsonconfig &);
|
||||
nano::error serialize_json (nano::jsonconfig &);
|
||||
/**
|
||||
* Returns true if an upgrade occurred
|
||||
* @param version The version to upgrade to.
|
||||
* @param config Configuration to upgrade.
|
||||
*/
|
||||
bool upgrade_json (unsigned version, nano::jsonconfig & config);
|
||||
bool rpc_enable;
|
||||
nano::rpc_config rpc;
|
||||
nano::node_config node;
|
||||
bool opencl_enable;
|
||||
nano::opencl_config opencl;
|
||||
static constexpr int json_version = 2;
|
||||
int json_version () const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/nano_wallet/icon.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
|
|
@ -21,135 +23,139 @@ public:
|
|||
nano::random_pool.GenerateBlock (wallet.bytes.data (), wallet.bytes.size ());
|
||||
assert (!wallet.is_zero ());
|
||||
}
|
||||
bool upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
|
||||
bool upgrade_json (unsigned version_a, nano::jsonconfig & json)
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
auto result (false);
|
||||
json.put ("version", json_version ());
|
||||
auto upgraded (false);
|
||||
switch (version_a)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
nano::account account;
|
||||
account.decode_account (tree_a.get<std::string> ("account"));
|
||||
tree_a.erase ("account");
|
||||
tree_a.put ("account", account.to_account ());
|
||||
tree_a.erase ("version");
|
||||
result = true;
|
||||
account.decode_account (json.get<std::string> ("account"));
|
||||
json.erase ("account");
|
||||
json.put ("account", account.to_account ());
|
||||
json.erase ("version");
|
||||
upgraded = true;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
boost::property_tree::ptree rpc_l;
|
||||
nano::jsonconfig rpc_l;
|
||||
rpc.serialize_json (rpc_l);
|
||||
tree_a.put ("rpc_enable", "false");
|
||||
tree_a.put_child ("rpc", rpc_l);
|
||||
tree_a.erase ("version");
|
||||
result = true;
|
||||
json.put ("rpc_enable", "false");
|
||||
json.put_child ("rpc", rpc_l);
|
||||
json.erase ("version");
|
||||
upgraded = true;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
auto opencl_enable_l (tree_a.get_optional<bool> ("opencl_enable"));
|
||||
auto opencl_enable_l (json.get_optional<bool> ("opencl_enable"));
|
||||
if (!opencl_enable_l)
|
||||
{
|
||||
tree_a.put ("opencl_enable", "false");
|
||||
json.put ("opencl_enable", "false");
|
||||
}
|
||||
auto opencl_l (tree_a.get_child_optional ("opencl"));
|
||||
auto opencl_l (json.get_optional_child ("opencl"));
|
||||
if (!opencl_l)
|
||||
{
|
||||
boost::property_tree::ptree opencl_l;
|
||||
nano::jsonconfig opencl_l;
|
||||
opencl.serialize_json (opencl_l);
|
||||
tree_a.put_child ("opencl", opencl_l);
|
||||
json.put_child ("opencl", opencl_l);
|
||||
}
|
||||
result = true;
|
||||
upgraded = true;
|
||||
}
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error ("Unknown qt_wallet_config version");
|
||||
}
|
||||
return result;
|
||||
return upgraded;
|
||||
}
|
||||
bool deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
|
||||
|
||||
nano::error deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
|
||||
{
|
||||
auto error (false);
|
||||
if (!tree_a.empty ())
|
||||
if (!json.empty ())
|
||||
{
|
||||
auto version_l (tree_a.get_optional<std::string> ("version"));
|
||||
auto version_l (json.get_optional<unsigned> ("version"));
|
||||
if (!version_l)
|
||||
{
|
||||
tree_a.put ("version", "1");
|
||||
version_l = "1";
|
||||
version_l = 1;
|
||||
json.put ("version", version_l.get ());
|
||||
upgraded_a = true;
|
||||
}
|
||||
upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
|
||||
auto wallet_l (tree_a.get<std::string> ("wallet"));
|
||||
auto account_l (tree_a.get<std::string> ("account"));
|
||||
auto & node_l (tree_a.get_child ("node"));
|
||||
rpc_enable = tree_a.get<bool> ("rpc_enable");
|
||||
auto & rpc_l (tree_a.get_child ("rpc"));
|
||||
opencl_enable = tree_a.get<bool> ("opencl_enable");
|
||||
auto & opencl_l (tree_a.get_child ("opencl"));
|
||||
try
|
||||
upgraded_a |= upgrade_json (version_l.get (), json);
|
||||
auto wallet_l (json.get<std::string> ("wallet"));
|
||||
auto account_l (json.get<std::string> ("account"));
|
||||
auto node_l (json.get_required_child ("node"));
|
||||
rpc_enable = json.get<bool> ("rpc_enable");
|
||||
auto rpc_l (json.get_required_child ("rpc"));
|
||||
opencl_enable = json.get<bool> ("opencl_enable");
|
||||
auto opencl_l (json.get_required_child ("opencl"));
|
||||
|
||||
if (wallet.decode_hex (wallet_l))
|
||||
{
|
||||
error |= wallet.decode_hex (wallet_l);
|
||||
error |= account.decode_account (account_l);
|
||||
error |= node.deserialize_json (upgraded_a, node_l);
|
||||
error |= rpc.deserialize_json (rpc_l);
|
||||
error |= opencl.deserialize_json (opencl_l);
|
||||
if (wallet.is_zero ())
|
||||
{
|
||||
nano::random_pool.GenerateBlock (wallet.bytes.data (), wallet.bytes.size ());
|
||||
upgraded_a = true;
|
||||
}
|
||||
json.get_error ().set ("Invalid wallet id. Did you open a node daemon config?");
|
||||
}
|
||||
catch (std::logic_error const &)
|
||||
else if (account.decode_account (account_l))
|
||||
{
|
||||
error = true;
|
||||
json.get_error ().set ("Invalid account");
|
||||
}
|
||||
node.deserialize_json (upgraded_a, node_l);
|
||||
rpc.deserialize_json (rpc_l);
|
||||
opencl.deserialize_json (opencl_l);
|
||||
if (wallet.is_zero ())
|
||||
{
|
||||
nano::random_pool.GenerateBlock (wallet.bytes.data (), wallet.bytes.size ());
|
||||
upgraded_a = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
serialize_json (tree_a);
|
||||
serialize_json (json);
|
||||
upgraded_a = true;
|
||||
}
|
||||
return error;
|
||||
return json.get_error ();
|
||||
}
|
||||
void serialize_json (boost::property_tree::ptree & tree_a)
|
||||
|
||||
void serialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
std::string wallet_string;
|
||||
wallet.encode_hex (wallet_string);
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
tree_a.put ("wallet", wallet_string);
|
||||
tree_a.put ("account", account.to_account ());
|
||||
boost::property_tree::ptree node_l;
|
||||
json.put ("version", json_version ());
|
||||
json.put ("wallet", wallet_string);
|
||||
json.put ("account", account.to_account ());
|
||||
nano::jsonconfig node_l;
|
||||
node.enable_voting = false;
|
||||
node.bootstrap_connections_max = 4;
|
||||
node.serialize_json (node_l);
|
||||
tree_a.add_child ("node", node_l);
|
||||
boost::property_tree::ptree rpc_l;
|
||||
json.put_child ("node", node_l);
|
||||
nano::jsonconfig rpc_l;
|
||||
rpc.serialize_json (rpc_l);
|
||||
tree_a.add_child ("rpc", rpc_l);
|
||||
tree_a.put ("rpc_enable", rpc_enable);
|
||||
tree_a.put ("opencl_enable", opencl_enable);
|
||||
boost::property_tree::ptree opencl_l;
|
||||
json.put_child ("rpc", rpc_l);
|
||||
json.put ("rpc_enable", rpc_enable);
|
||||
json.put ("opencl_enable", opencl_enable);
|
||||
nano::jsonconfig opencl_l;
|
||||
opencl.serialize_json (opencl_l);
|
||||
tree_a.add_child ("opencl", opencl_l);
|
||||
json.put_child ("opencl", opencl_l);
|
||||
}
|
||||
|
||||
bool serialize_json_stream (std::ostream & stream_a)
|
||||
{
|
||||
auto result (false);
|
||||
stream_a.seekp (0);
|
||||
try
|
||||
{
|
||||
boost::property_tree::ptree tree;
|
||||
serialize_json (tree);
|
||||
boost::property_tree::write_json (stream_a, tree);
|
||||
nano::jsonconfig json;
|
||||
serialize_json (json);
|
||||
json.write (stream_a);
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
std::cerr << ex.what () << std::endl;
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nano::uint256_union wallet;
|
||||
nano::account account;
|
||||
nano::node_config node;
|
||||
|
|
@ -157,7 +163,10 @@ public:
|
|||
nano::rpc_config rpc;
|
||||
bool opencl_enable;
|
||||
nano::opencl_config opencl;
|
||||
static constexpr int json_version = 4;
|
||||
int json_version () const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
|
|
@ -169,19 +178,23 @@ void show_error (std::string const & message_a)
|
|||
message.show ();
|
||||
message.exec ();
|
||||
}
|
||||
bool update_config (qt_wallet_config & config_a, boost::filesystem::path const & config_path_a, std::fstream & config_file_a)
|
||||
bool update_config (qt_wallet_config & config_a, boost::filesystem::path const & config_path_a)
|
||||
{
|
||||
auto account (config_a.account);
|
||||
auto wallet (config_a.wallet);
|
||||
auto error (false);
|
||||
if (!nano::fetch_object (config_a, config_path_a))
|
||||
nano::jsonconfig config;
|
||||
if (!config.read_and_update (config_a, config_path_a))
|
||||
{
|
||||
if (account != config_a.account || wallet != config_a.wallet)
|
||||
{
|
||||
config_a.account = account;
|
||||
config_a.wallet = wallet;
|
||||
config_file_a.open (config_path_a.string (), std::ios_base::out | std::ios_base::trunc);
|
||||
error = config_a.serialize_json_stream (config_file_a);
|
||||
|
||||
// Update json file with new account and/or wallet values
|
||||
std::fstream config_file;
|
||||
config_file.open (config_path_a.string (), std::ios_base::out | std::ios_base::trunc);
|
||||
error = config_a.serialize_json_stream (config_file);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
|
|
@ -203,9 +216,8 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
|
|||
qt_wallet_config config (data_path);
|
||||
auto config_path ((data_path / "config.json"));
|
||||
int result (0);
|
||||
std::fstream config_file;
|
||||
auto error (nano::fetch_object (config, config_path));
|
||||
config_file.close ();
|
||||
nano::jsonconfig json;
|
||||
auto error (json.read_and_update (config, config_path));
|
||||
nano::set_secure_perm_file (config_path, error_chmod);
|
||||
if (!error)
|
||||
{
|
||||
|
|
@ -253,7 +265,7 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
|
|||
}
|
||||
}
|
||||
assert (wallet->exists (config.account));
|
||||
update_config (config, config_path, config_file);
|
||||
update_config (config, config_path);
|
||||
node->start ();
|
||||
std::unique_ptr<nano::rpc> rpc = get_rpc (io_ctx, *node, config.rpc);
|
||||
if (rpc && config.rpc_enable)
|
||||
|
|
@ -276,13 +288,15 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
|
|||
}
|
||||
else
|
||||
{
|
||||
splash->hide ();
|
||||
show_error ("Error initializing node");
|
||||
}
|
||||
update_config (config, config_path, config_file);
|
||||
update_config (config, config_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_error ("Error deserializing config");
|
||||
splash->hide ();
|
||||
show_error ("Error deserializing config: " + json.get_error ().get_message ());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
#include <boost/log/utility/setup/console.hpp>
|
||||
#include <boost/log/utility/setup/file.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <nano/node/logging.hpp>
|
||||
|
||||
nano::logging::logging () :
|
||||
|
|
@ -42,104 +43,106 @@ void nano::logging::init (boost::filesystem::path const & application_path_a)
|
|||
}
|
||||
}
|
||||
|
||||
void nano::logging::serialize_json (boost::property_tree::ptree & tree_a) const
|
||||
nano::error nano::logging::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
tree_a.put ("ledger", ledger_logging_value);
|
||||
tree_a.put ("ledger_duplicate", ledger_duplicate_logging_value);
|
||||
tree_a.put ("vote", vote_logging_value);
|
||||
tree_a.put ("network", network_logging_value);
|
||||
tree_a.put ("network_message", network_message_logging_value);
|
||||
tree_a.put ("network_publish", network_publish_logging_value);
|
||||
tree_a.put ("network_packet", network_packet_logging_value);
|
||||
tree_a.put ("network_keepalive", network_keepalive_logging_value);
|
||||
tree_a.put ("network_node_id_handshake", network_node_id_handshake_logging_value);
|
||||
tree_a.put ("node_lifetime_tracing", node_lifetime_tracing_value);
|
||||
tree_a.put ("insufficient_work", insufficient_work_logging_value);
|
||||
tree_a.put ("log_rpc", log_rpc_value);
|
||||
tree_a.put ("bulk_pull", bulk_pull_logging_value);
|
||||
tree_a.put ("work_generation_time", work_generation_time_value);
|
||||
tree_a.put ("upnp_details", upnp_details_logging_value);
|
||||
tree_a.put ("timing", timing_logging_value);
|
||||
tree_a.put ("log_to_cerr", log_to_cerr_value);
|
||||
tree_a.put ("max_size", max_size);
|
||||
tree_a.put ("rotation_size", rotation_size);
|
||||
tree_a.put ("flush", flush);
|
||||
json.put ("version", json_version ());
|
||||
json.put ("ledger", ledger_logging_value);
|
||||
json.put ("ledger_duplicate", ledger_duplicate_logging_value);
|
||||
json.put ("vote", vote_logging_value);
|
||||
json.put ("network", network_logging_value);
|
||||
json.put ("network_message", network_message_logging_value);
|
||||
json.put ("network_publish", network_publish_logging_value);
|
||||
json.put ("network_packet", network_packet_logging_value);
|
||||
json.put ("network_keepalive", network_keepalive_logging_value);
|
||||
json.put ("network_node_id_handshake", network_node_id_handshake_logging_value);
|
||||
json.put ("node_lifetime_tracing", node_lifetime_tracing_value);
|
||||
json.put ("insufficient_work", insufficient_work_logging_value);
|
||||
json.put ("log_rpc", log_rpc_value);
|
||||
json.put ("bulk_pull", bulk_pull_logging_value);
|
||||
json.put ("work_generation_time", work_generation_time_value);
|
||||
json.put ("upnp_details", upnp_details_logging_value);
|
||||
json.put ("timing", timing_logging_value);
|
||||
json.put ("log_to_cerr", log_to_cerr_value);
|
||||
json.put ("max_size", max_size);
|
||||
json.put ("rotation_size", rotation_size);
|
||||
json.put ("flush", flush);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano::logging::upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
|
||||
bool nano::logging::upgrade_json (unsigned version_a, nano::jsonconfig & json)
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
auto result (false);
|
||||
json.put ("version", json_version ());
|
||||
auto upgraded_l (false);
|
||||
switch (version_a)
|
||||
{
|
||||
case 1:
|
||||
tree_a.put ("vote", vote_logging_value);
|
||||
result = true;
|
||||
json.put ("vote", vote_logging_value);
|
||||
upgraded_l = true;
|
||||
case 2:
|
||||
tree_a.put ("rotation_size", "4194304");
|
||||
tree_a.put ("flush", "true");
|
||||
result = true;
|
||||
json.put ("rotation_size", rotation_size);
|
||||
json.put ("flush", true);
|
||||
upgraded_l = true;
|
||||
case 3:
|
||||
tree_a.put ("network_node_id_handshake", "false");
|
||||
result = true;
|
||||
json.put ("network_node_id_handshake", false);
|
||||
upgraded_l = true;
|
||||
case 4:
|
||||
tree_a.put ("upnp_details", "false");
|
||||
tree_a.put ("timing", "false");
|
||||
result = true;
|
||||
json.put ("upnp_details", "false");
|
||||
json.put ("timing", "false");
|
||||
upgraded_l = true;
|
||||
case 5:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error ("Unknown logging_config version");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
return upgraded_l;
|
||||
}
|
||||
|
||||
bool nano::logging::deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
|
||||
nano::error nano::logging::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
|
||||
{
|
||||
auto result (false);
|
||||
try
|
||||
int version_l;
|
||||
if (!json.has_key ("version"))
|
||||
{
|
||||
auto version_l (tree_a.get_optional<std::string> ("version"));
|
||||
if (!version_l)
|
||||
version_l = 1;
|
||||
json.put ("version", version_l);
|
||||
|
||||
boost::optional<nano::jsonconfig> work_peers_l;
|
||||
json.get_optional_child ("work_peers", work_peers_l);
|
||||
if (!work_peers_l)
|
||||
{
|
||||
tree_a.put ("version", "1");
|
||||
version_l = "1";
|
||||
auto work_peers_l (tree_a.get_child_optional ("work_peers"));
|
||||
if (!work_peers_l)
|
||||
{
|
||||
tree_a.add_child ("work_peers", boost::property_tree::ptree ());
|
||||
}
|
||||
upgraded_a = true;
|
||||
nano::jsonconfig peers;
|
||||
json.put_child ("work_peers", peers);
|
||||
}
|
||||
upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
|
||||
ledger_logging_value = tree_a.get<bool> ("ledger");
|
||||
ledger_duplicate_logging_value = tree_a.get<bool> ("ledger_duplicate");
|
||||
vote_logging_value = tree_a.get<bool> ("vote");
|
||||
network_logging_value = tree_a.get<bool> ("network");
|
||||
network_message_logging_value = tree_a.get<bool> ("network_message");
|
||||
network_publish_logging_value = tree_a.get<bool> ("network_publish");
|
||||
network_packet_logging_value = tree_a.get<bool> ("network_packet");
|
||||
network_keepalive_logging_value = tree_a.get<bool> ("network_keepalive");
|
||||
network_node_id_handshake_logging_value = tree_a.get<bool> ("network_node_id_handshake");
|
||||
node_lifetime_tracing_value = tree_a.get<bool> ("node_lifetime_tracing");
|
||||
insufficient_work_logging_value = tree_a.get<bool> ("insufficient_work");
|
||||
log_rpc_value = tree_a.get<bool> ("log_rpc");
|
||||
bulk_pull_logging_value = tree_a.get<bool> ("bulk_pull");
|
||||
work_generation_time_value = tree_a.get<bool> ("work_generation_time");
|
||||
upnp_details_logging_value = tree_a.get<bool> ("upnp_details");
|
||||
timing_logging_value = tree_a.get<bool> ("timing");
|
||||
log_to_cerr_value = tree_a.get<bool> ("log_to_cerr");
|
||||
max_size = tree_a.get<uintmax_t> ("max_size");
|
||||
rotation_size = tree_a.get<uintmax_t> ("rotation_size", 4194304);
|
||||
flush = tree_a.get<bool> ("flush", true);
|
||||
upgraded_a = true;
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
else
|
||||
{
|
||||
result = true;
|
||||
json.get_required<int> ("version", version_l);
|
||||
}
|
||||
return result;
|
||||
|
||||
upgraded_a |= upgrade_json (version_l, json);
|
||||
json.get<bool> ("ledger", ledger_logging_value);
|
||||
json.get<bool> ("ledger_duplicate", ledger_duplicate_logging_value);
|
||||
json.get<bool> ("vote", vote_logging_value);
|
||||
json.get<bool> ("network", network_logging_value);
|
||||
json.get<bool> ("network_message", network_message_logging_value);
|
||||
json.get<bool> ("network_publish", network_publish_logging_value);
|
||||
json.get<bool> ("network_packet", network_packet_logging_value);
|
||||
json.get<bool> ("network_keepalive", network_keepalive_logging_value);
|
||||
json.get<bool> ("network_node_id_handshake", network_node_id_handshake_logging_value);
|
||||
json.get<bool> ("node_lifetime_tracing", node_lifetime_tracing_value);
|
||||
json.get<bool> ("insufficient_work", insufficient_work_logging_value);
|
||||
json.get<bool> ("log_rpc", log_rpc_value);
|
||||
json.get<bool> ("bulk_pull", bulk_pull_logging_value);
|
||||
json.get<bool> ("work_generation_time", work_generation_time_value);
|
||||
json.get<bool> ("upnp_details", upnp_details_logging_value);
|
||||
json.get<bool> ("timing", timing_logging_value);
|
||||
json.get<bool> ("log_to_cerr", log_to_cerr_value);
|
||||
json.get<bool> ("flush", flush);
|
||||
json.get<uintmax_t> ("max_size", max_size);
|
||||
json.get<uintmax_t> ("rotation_size", rotation_size);
|
||||
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano::logging::ledger_logging () const
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/sources/logger.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <cstdint>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
|
||||
#define FATAL_LOG_PREFIX "FATAL ERROR: "
|
||||
|
||||
|
|
@ -14,9 +15,9 @@ class logging
|
|||
{
|
||||
public:
|
||||
logging ();
|
||||
void serialize_json (boost::property_tree::ptree &) const;
|
||||
bool deserialize_json (bool &, boost::property_tree::ptree &);
|
||||
bool upgrade_json (unsigned, boost::property_tree::ptree &);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (bool &, nano::jsonconfig &);
|
||||
bool upgrade_json (unsigned, nano::jsonconfig &);
|
||||
bool ledger_logging () const;
|
||||
bool ledger_duplicate_logging () const;
|
||||
bool vote_logging () const;
|
||||
|
|
@ -58,6 +59,9 @@ public:
|
|||
uintmax_t max_size;
|
||||
uintmax_t rotation_size;
|
||||
boost::log::sources::logger_mt log;
|
||||
static constexpr int json_version = 5;
|
||||
int json_version () const
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/nodeconfig.hpp>
|
||||
// NOTE: to reduce compile times, this include can be replaced by more narrow includes
|
||||
// once nano::network is factored out of node.{c|h}pp
|
||||
|
|
@ -61,262 +62,270 @@ block_processor_batch_max_time (std::chrono::milliseconds (5000))
|
|||
}
|
||||
}
|
||||
|
||||
void nano::node_config::serialize_json (boost::property_tree::ptree & tree_a) const
|
||||
nano::error nano::node_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
tree_a.put ("peering_port", std::to_string (peering_port));
|
||||
tree_a.put ("bootstrap_fraction_numerator", std::to_string (bootstrap_fraction_numerator));
|
||||
tree_a.put ("receive_minimum", receive_minimum.to_string_dec ());
|
||||
boost::property_tree::ptree logging_l;
|
||||
json.put ("version", json_version ());
|
||||
json.put ("peering_port", peering_port);
|
||||
json.put ("bootstrap_fraction_numerator", bootstrap_fraction_numerator);
|
||||
json.put ("receive_minimum", receive_minimum.to_string_dec ());
|
||||
|
||||
nano::jsonconfig logging_l;
|
||||
logging.serialize_json (logging_l);
|
||||
tree_a.add_child ("logging", logging_l);
|
||||
boost::property_tree::ptree work_peers_l;
|
||||
json.put_child ("logging", logging_l);
|
||||
|
||||
nano::jsonconfig work_peers_l;
|
||||
for (auto i (work_peers.begin ()), n (work_peers.end ()); i != n; ++i)
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("", boost::str (boost::format ("%1%:%2%") % i->first % i->second));
|
||||
work_peers_l.push_back (std::make_pair ("", entry));
|
||||
work_peers_l.push (boost::str (boost::format ("%1%:%2%") % i->first % i->second));
|
||||
}
|
||||
tree_a.add_child ("work_peers", work_peers_l);
|
||||
boost::property_tree::ptree preconfigured_peers_l;
|
||||
json.put_child ("work_peers", work_peers_l);
|
||||
nano::jsonconfig preconfigured_peers_l;
|
||||
for (auto i (preconfigured_peers.begin ()), n (preconfigured_peers.end ()); i != n; ++i)
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("", *i);
|
||||
preconfigured_peers_l.push_back (std::make_pair ("", entry));
|
||||
preconfigured_peers_l.push (*i);
|
||||
}
|
||||
tree_a.add_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
boost::property_tree::ptree preconfigured_representatives_l;
|
||||
json.put_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
|
||||
nano::jsonconfig preconfigured_representatives_l;
|
||||
for (auto i (preconfigured_representatives.begin ()), n (preconfigured_representatives.end ()); i != n; ++i)
|
||||
{
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("", i->to_account ());
|
||||
preconfigured_representatives_l.push_back (std::make_pair ("", entry));
|
||||
preconfigured_representatives_l.push (i->to_account ());
|
||||
}
|
||||
tree_a.add_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
|
||||
tree_a.put ("online_weight_quorum", std::to_string (online_weight_quorum));
|
||||
tree_a.put ("password_fanout", std::to_string (password_fanout));
|
||||
tree_a.put ("io_threads", std::to_string (io_threads));
|
||||
tree_a.put ("network_threads", std::to_string (network_threads));
|
||||
tree_a.put ("work_threads", std::to_string (work_threads));
|
||||
tree_a.put ("enable_voting", enable_voting);
|
||||
tree_a.put ("bootstrap_connections", bootstrap_connections);
|
||||
tree_a.put ("bootstrap_connections_max", bootstrap_connections_max);
|
||||
tree_a.put ("callback_address", callback_address);
|
||||
tree_a.put ("callback_port", std::to_string (callback_port));
|
||||
tree_a.put ("callback_target", callback_target);
|
||||
tree_a.put ("lmdb_max_dbs", lmdb_max_dbs);
|
||||
tree_a.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
|
||||
tree_a.put ("allow_local_peers", allow_local_peers);
|
||||
json.put_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
|
||||
json.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
|
||||
json.put ("online_weight_quorum", online_weight_quorum);
|
||||
json.put ("password_fanout", password_fanout);
|
||||
json.put ("io_threads", io_threads);
|
||||
json.put ("network_threads", network_threads);
|
||||
json.put ("work_threads", work_threads);
|
||||
json.put ("enable_voting", enable_voting);
|
||||
json.put ("bootstrap_connections", bootstrap_connections);
|
||||
json.put ("bootstrap_connections_max", bootstrap_connections_max);
|
||||
json.put ("callback_address", callback_address);
|
||||
json.put ("callback_port", callback_port);
|
||||
json.put ("callback_target", callback_target);
|
||||
json.put ("lmdb_max_dbs", lmdb_max_dbs);
|
||||
json.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
|
||||
json.put ("allow_local_peers", allow_local_peers);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano::node_config::upgrade_json (unsigned version_a, boost::property_tree::ptree & tree_a)
|
||||
bool nano::node_config::upgrade_json (unsigned version_a, nano::jsonconfig & json)
|
||||
{
|
||||
tree_a.put ("version", std::to_string (json_version));
|
||||
auto result (false);
|
||||
json.put ("version", json_version ());
|
||||
auto upgraded (false);
|
||||
switch (version_a)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
auto reps_l (tree_a.get_child ("preconfigured_representatives"));
|
||||
boost::property_tree::ptree reps;
|
||||
for (auto i (reps_l.begin ()), n (reps_l.end ()); i != n; ++i)
|
||||
{
|
||||
nano::jsonconfig reps_l;
|
||||
json.get_required_child ("preconfigured_representatives", reps_l);
|
||||
nano::jsonconfig reps;
|
||||
reps_l.array_entries<std::string> ([&reps](std::string entry) {
|
||||
nano::uint256_union account;
|
||||
account.decode_account (i->second.get<std::string> (""));
|
||||
boost::property_tree::ptree entry;
|
||||
entry.put ("", account.to_account ());
|
||||
reps.push_back (std::make_pair ("", entry));
|
||||
}
|
||||
tree_a.erase ("preconfigured_representatives");
|
||||
tree_a.add_child ("preconfigured_representatives", reps);
|
||||
result = true;
|
||||
account.decode_account (entry);
|
||||
reps.push (account.to_account ());
|
||||
});
|
||||
|
||||
json.replace_child ("preconfigured_representatives", reps);
|
||||
upgraded = true;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
tree_a.put ("inactive_supply", nano::uint128_union (0).to_string_dec ());
|
||||
tree_a.put ("password_fanout", std::to_string (1024));
|
||||
tree_a.put ("io_threads", std::to_string (io_threads));
|
||||
tree_a.put ("work_threads", std::to_string (work_threads));
|
||||
result = true;
|
||||
json.put ("inactive_supply", nano::uint128_union (0).to_string_dec ());
|
||||
json.put ("password_fanout", std::to_string (1024));
|
||||
json.put ("io_threads", std::to_string (io_threads));
|
||||
json.put ("work_threads", std::to_string (work_threads));
|
||||
upgraded = true;
|
||||
}
|
||||
case 3:
|
||||
tree_a.erase ("receive_minimum");
|
||||
tree_a.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
|
||||
result = true;
|
||||
json.erase ("receive_minimum");
|
||||
json.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
|
||||
upgraded = true;
|
||||
case 4:
|
||||
tree_a.erase ("receive_minimum");
|
||||
tree_a.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
|
||||
result = true;
|
||||
json.erase ("receive_minimum");
|
||||
json.put ("receive_minimum", nano::xrb_ratio.convert_to<std::string> ());
|
||||
upgraded = true;
|
||||
case 5:
|
||||
tree_a.put ("enable_voting", enable_voting);
|
||||
tree_a.erase ("packet_delay_microseconds");
|
||||
tree_a.erase ("rebroadcast_delay");
|
||||
tree_a.erase ("creation_rebroadcast");
|
||||
result = true;
|
||||
json.put ("enable_voting", enable_voting);
|
||||
json.erase ("packet_delay_microseconds");
|
||||
json.erase ("rebroadcast_delay");
|
||||
json.erase ("creation_rebroadcast");
|
||||
upgraded = true;
|
||||
case 6:
|
||||
tree_a.put ("bootstrap_connections", 16);
|
||||
tree_a.put ("callback_address", "");
|
||||
tree_a.put ("callback_port", "0");
|
||||
tree_a.put ("callback_target", "");
|
||||
result = true;
|
||||
json.put ("bootstrap_connections", 16);
|
||||
json.put ("callback_address", "");
|
||||
json.put ("callback_port", 0);
|
||||
json.put ("callback_target", "");
|
||||
upgraded = true;
|
||||
case 7:
|
||||
tree_a.put ("lmdb_max_dbs", "128");
|
||||
result = true;
|
||||
json.put ("lmdb_max_dbs", 128);
|
||||
upgraded = true;
|
||||
case 8:
|
||||
tree_a.put ("bootstrap_connections_max", "64");
|
||||
result = true;
|
||||
json.put ("bootstrap_connections_max", "64");
|
||||
upgraded = true;
|
||||
case 9:
|
||||
tree_a.put ("state_block_parse_canary", nano::block_hash (0).to_string ());
|
||||
tree_a.put ("state_block_generate_canary", nano::block_hash (0).to_string ());
|
||||
result = true;
|
||||
json.put ("state_block_parse_canary", nano::block_hash (0).to_string ());
|
||||
json.put ("state_block_generate_canary", nano::block_hash (0).to_string ());
|
||||
upgraded = true;
|
||||
case 10:
|
||||
tree_a.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
|
||||
tree_a.put ("online_weight_quorom", std::to_string (online_weight_quorum));
|
||||
tree_a.erase ("inactive_supply");
|
||||
result = true;
|
||||
json.put ("online_weight_minimum", online_weight_minimum.to_string_dec ());
|
||||
json.put ("online_weight_quorom", std::to_string (online_weight_quorum));
|
||||
json.erase ("inactive_supply");
|
||||
upgraded = true;
|
||||
case 11:
|
||||
{
|
||||
auto online_weight_quorum_l (tree_a.get<std::string> ("online_weight_quorom"));
|
||||
tree_a.erase ("online_weight_quorom");
|
||||
tree_a.put ("online_weight_quorum", online_weight_quorum_l);
|
||||
result = true;
|
||||
// Rename
|
||||
std::string online_weight_quorum_l;
|
||||
json.get<std::string> ("online_weight_quorom", online_weight_quorum_l);
|
||||
json.erase ("online_weight_quorom");
|
||||
json.put ("online_weight_quorum", online_weight_quorum_l);
|
||||
upgraded = true;
|
||||
}
|
||||
case 12:
|
||||
tree_a.erase ("state_block_parse_canary");
|
||||
tree_a.erase ("state_block_generate_canary");
|
||||
result = true;
|
||||
json.erase ("state_block_parse_canary");
|
||||
json.erase ("state_block_generate_canary");
|
||||
upgraded = true;
|
||||
case 13:
|
||||
tree_a.put ("generate_hash_votes_at", "0");
|
||||
result = true;
|
||||
json.put ("generate_hash_votes_at", 0);
|
||||
upgraded = true;
|
||||
case 14:
|
||||
tree_a.put ("network_threads", std::to_string (network_threads));
|
||||
tree_a.erase ("generate_hash_votes_at");
|
||||
tree_a.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
|
||||
result = true;
|
||||
json.put ("network_threads", std::to_string (network_threads));
|
||||
json.erase ("generate_hash_votes_at");
|
||||
json.put ("block_processor_batch_max_time", block_processor_batch_max_time.count ());
|
||||
upgraded = true;
|
||||
case 15:
|
||||
tree_a.put ("allow_local_peers", allow_local_peers);
|
||||
result = true;
|
||||
json.put ("allow_local_peers", allow_local_peers);
|
||||
upgraded = true;
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error ("Unknown node_config version");
|
||||
}
|
||||
return result;
|
||||
return upgraded;
|
||||
}
|
||||
|
||||
bool nano::node_config::deserialize_json (bool & upgraded_a, boost::property_tree::ptree & tree_a)
|
||||
nano::error nano::node_config::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
|
||||
{
|
||||
auto result (false);
|
||||
try
|
||||
{
|
||||
auto version_l (tree_a.get_optional<std::string> ("version"));
|
||||
auto version_l (json.get_optional<unsigned> ("version"));
|
||||
if (!version_l)
|
||||
{
|
||||
tree_a.put ("version", "1");
|
||||
version_l = "1";
|
||||
auto work_peers_l (tree_a.get_child_optional ("work_peers"));
|
||||
version_l = 1;
|
||||
json.put ("version", version_l);
|
||||
auto work_peers_l (json.get_optional_child ("work_peers"));
|
||||
if (!work_peers_l)
|
||||
{
|
||||
tree_a.add_child ("work_peers", boost::property_tree::ptree ());
|
||||
nano::jsonconfig empty;
|
||||
json.put_child ("work_peers", empty);
|
||||
}
|
||||
upgraded_a = true;
|
||||
}
|
||||
upgraded_a |= upgrade_json (std::stoull (version_l.get ()), tree_a);
|
||||
auto peering_port_l (tree_a.get<std::string> ("peering_port"));
|
||||
auto bootstrap_fraction_numerator_l (tree_a.get<std::string> ("bootstrap_fraction_numerator"));
|
||||
auto receive_minimum_l (tree_a.get<std::string> ("receive_minimum"));
|
||||
auto & logging_l (tree_a.get_child ("logging"));
|
||||
|
||||
upgraded_a |= upgrade_json (version_l.get (), json);
|
||||
|
||||
auto logging_l (json.get_required_child ("logging"));
|
||||
logging.deserialize_json (upgraded_a, logging_l);
|
||||
|
||||
work_peers.clear ();
|
||||
auto work_peers_l (tree_a.get_child ("work_peers"));
|
||||
for (auto i (work_peers_l.begin ()), n (work_peers_l.end ()); i != n; ++i)
|
||||
{
|
||||
auto work_peer (i->second.get<std::string> (""));
|
||||
auto port_position (work_peer.rfind (':'));
|
||||
result |= port_position == -1;
|
||||
auto work_peers_l (json.get_required_child ("work_peers"));
|
||||
work_peers_l.array_entries<std::string> ([this](std::string entry) {
|
||||
auto port_position (entry.rfind (':'));
|
||||
bool result = port_position == -1;
|
||||
if (!result)
|
||||
{
|
||||
auto port_str (work_peer.substr (port_position + 1));
|
||||
auto port_str (entry.substr (port_position + 1));
|
||||
uint16_t port;
|
||||
result |= parse_port (port_str, port);
|
||||
if (!result)
|
||||
{
|
||||
auto address (work_peer.substr (0, port_position));
|
||||
work_peers.push_back (std::make_pair (address, port));
|
||||
auto address (entry.substr (0, port_position));
|
||||
this->work_peers.push_back (std::make_pair (address, port));
|
||||
}
|
||||
}
|
||||
}
|
||||
auto preconfigured_peers_l (tree_a.get_child ("preconfigured_peers"));
|
||||
});
|
||||
|
||||
nano::jsonconfig preconfigured_peers_l;
|
||||
json.get_required_child ("preconfigured_peers", preconfigured_peers_l);
|
||||
preconfigured_peers.clear ();
|
||||
for (auto i (preconfigured_peers_l.begin ()), n (preconfigured_peers_l.end ()); i != n; ++i)
|
||||
{
|
||||
auto bootstrap_peer (i->second.get<std::string> (""));
|
||||
preconfigured_peers.push_back (bootstrap_peer);
|
||||
}
|
||||
auto preconfigured_representatives_l (tree_a.get_child ("preconfigured_representatives"));
|
||||
preconfigured_peers_l.array_entries<std::string> ([this](std::string entry) {
|
||||
preconfigured_peers.push_back (entry);
|
||||
});
|
||||
|
||||
nano::jsonconfig preconfigured_representatives_l;
|
||||
json.get_required_child ("preconfigured_representatives", preconfigured_representatives_l);
|
||||
preconfigured_representatives.clear ();
|
||||
for (auto i (preconfigured_representatives_l.begin ()), n (preconfigured_representatives_l.end ()); i != n; ++i)
|
||||
{
|
||||
preconfigured_representatives_l.array_entries<std::string> ([this, &json](std::string entry) {
|
||||
nano::account representative (0);
|
||||
result = result || representative.decode_account (i->second.get<std::string> (""));
|
||||
if (representative.decode_account (entry))
|
||||
{
|
||||
json.get_error ().set ("Invalid representative account: " + entry);
|
||||
}
|
||||
preconfigured_representatives.push_back (representative);
|
||||
}
|
||||
});
|
||||
|
||||
if (preconfigured_representatives.empty ())
|
||||
{
|
||||
result = true;
|
||||
json.get_error ().set ("At least one representative account must be set");
|
||||
}
|
||||
auto stat_config_l (tree_a.get_child_optional ("statistics"));
|
||||
auto stat_config_l (json.get_optional_child ("statistics"));
|
||||
if (stat_config_l)
|
||||
{
|
||||
result |= stat_config.deserialize_json (stat_config_l.get ());
|
||||
stat_config.deserialize_json (stat_config_l.get ());
|
||||
}
|
||||
auto online_weight_minimum_l (tree_a.get<std::string> ("online_weight_minimum"));
|
||||
auto online_weight_quorum_l (tree_a.get<std::string> ("online_weight_quorum"));
|
||||
auto password_fanout_l (tree_a.get<std::string> ("password_fanout"));
|
||||
auto io_threads_l (tree_a.get<std::string> ("io_threads"));
|
||||
auto work_threads_l (tree_a.get<std::string> ("work_threads"));
|
||||
enable_voting = tree_a.get<bool> ("enable_voting");
|
||||
auto bootstrap_connections_l (tree_a.get<std::string> ("bootstrap_connections"));
|
||||
auto bootstrap_connections_max_l (tree_a.get<std::string> ("bootstrap_connections_max"));
|
||||
callback_address = tree_a.get<std::string> ("callback_address");
|
||||
auto callback_port_l (tree_a.get<std::string> ("callback_port"));
|
||||
callback_target = tree_a.get<std::string> ("callback_target");
|
||||
auto lmdb_max_dbs_l = tree_a.get<std::string> ("lmdb_max_dbs");
|
||||
result |= parse_port (callback_port_l, callback_port);
|
||||
auto block_processor_batch_max_time_l = tree_a.get<std::string> ("block_processor_batch_max_time");
|
||||
try
|
||||
|
||||
auto receive_minimum_l (json.get<std::string> ("receive_minimum"));
|
||||
if (receive_minimum.decode_dec (receive_minimum_l))
|
||||
{
|
||||
peering_port = std::stoul (peering_port_l);
|
||||
bootstrap_fraction_numerator = std::stoul (bootstrap_fraction_numerator_l);
|
||||
password_fanout = std::stoul (password_fanout_l);
|
||||
io_threads = std::stoul (io_threads_l);
|
||||
network_threads = tree_a.get<unsigned> ("network_threads", network_threads);
|
||||
work_threads = std::stoul (work_threads_l);
|
||||
bootstrap_connections = std::stoul (bootstrap_connections_l);
|
||||
bootstrap_connections_max = std::stoul (bootstrap_connections_max_l);
|
||||
lmdb_max_dbs = std::stoi (lmdb_max_dbs_l);
|
||||
online_weight_quorum = std::stoul (online_weight_quorum_l);
|
||||
block_processor_batch_max_time = std::chrono::milliseconds (std::stoul (block_processor_batch_max_time_l));
|
||||
result |= peering_port > std::numeric_limits<uint16_t>::max ();
|
||||
result |= logging.deserialize_json (upgraded_a, logging_l);
|
||||
result |= receive_minimum.decode_dec (receive_minimum_l);
|
||||
result |= online_weight_minimum.decode_dec (online_weight_minimum_l);
|
||||
result |= online_weight_quorum > 100;
|
||||
result |= password_fanout < 16;
|
||||
result |= password_fanout > 1024 * 1024;
|
||||
result |= io_threads == 0;
|
||||
json.get_error ().set ("receive_minimum contains an invalid decimal amount");
|
||||
}
|
||||
catch (std::logic_error const &)
|
||||
|
||||
auto online_weight_minimum_l (json.get<std::string> ("online_weight_minimum"));
|
||||
if (online_weight_minimum.decode_dec (online_weight_minimum_l))
|
||||
{
|
||||
result = true;
|
||||
json.get_error ().set ("online_weight_minimum contains an invalid decimal amount");
|
||||
}
|
||||
|
||||
auto block_processor_batch_max_time_l (json.get<unsigned long> ("block_processor_batch_max_time"));
|
||||
block_processor_batch_max_time = std::chrono::milliseconds (block_processor_batch_max_time_l);
|
||||
|
||||
json.get<uint16_t> ("peering_port", peering_port);
|
||||
json.get<unsigned> ("bootstrap_fraction_numerator", bootstrap_fraction_numerator);
|
||||
json.get<unsigned> ("online_weight_quorum", online_weight_quorum);
|
||||
json.get<unsigned> ("password_fanout", password_fanout);
|
||||
json.get<unsigned> ("io_threads", io_threads);
|
||||
json.get<unsigned> ("work_threads", work_threads);
|
||||
json.get<unsigned> ("network_threads", network_threads);
|
||||
json.get<unsigned> ("bootstrap_connections", bootstrap_connections);
|
||||
json.get<unsigned> ("bootstrap_connections_max", bootstrap_connections_max);
|
||||
json.get<std::string> ("callback_address", callback_address);
|
||||
json.get<uint16_t> ("callback_port", callback_port);
|
||||
json.get<std::string> ("callback_target", callback_target);
|
||||
json.get<int> ("lmdb_max_dbs", lmdb_max_dbs);
|
||||
json.get<bool> ("enable_voting", enable_voting);
|
||||
|
||||
// Validate ranges
|
||||
|
||||
if (online_weight_quorum > 100)
|
||||
{
|
||||
json.get_error ().set ("online_weight_quorum must be less than 100");
|
||||
}
|
||||
if (password_fanout < 16 || password_fanout > 1024 * 1024)
|
||||
{
|
||||
json.get_error ().set ("password_fanout must a number between 16 and 1048576");
|
||||
}
|
||||
if (io_threads == 0)
|
||||
{
|
||||
json.get_error ().set ("io_threads must be non-zero");
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
catch (std::runtime_error const & ex)
|
||||
{
|
||||
result = true;
|
||||
json.get_error ().set (ex.what ());
|
||||
}
|
||||
return result;
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::account nano::node_config::random_representative ()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <chrono>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/node/logging.hpp>
|
||||
#include <nano/node/stats.hpp>
|
||||
|
|
@ -17,9 +18,9 @@ class node_config
|
|||
public:
|
||||
node_config ();
|
||||
node_config (uint16_t, nano::logging const &);
|
||||
void serialize_json (boost::property_tree::ptree &) const;
|
||||
bool deserialize_json (bool &, boost::property_tree::ptree &);
|
||||
bool upgrade_json (unsigned, boost::property_tree::ptree &);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (bool &, nano::jsonconfig &);
|
||||
bool upgrade_json (unsigned, nano::jsonconfig &);
|
||||
nano::account random_representative ();
|
||||
uint16_t peering_port;
|
||||
nano::logging logging;
|
||||
|
|
@ -49,7 +50,10 @@ public:
|
|||
static std::chrono::seconds constexpr keepalive_period = std::chrono::seconds (60);
|
||||
static std::chrono::seconds constexpr keepalive_cutoff = keepalive_period * 5;
|
||||
static std::chrono::minutes constexpr wallet_backup_interval = std::chrono::minutes (5);
|
||||
static constexpr int json_version = 16;
|
||||
inline int json_version () const
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
};
|
||||
|
||||
class node_flags
|
||||
|
|
|
|||
|
|
@ -512,37 +512,20 @@ threads (threads_a)
|
|||
{
|
||||
}
|
||||
|
||||
void nano::opencl_config::serialize_json (boost::property_tree::ptree & tree_a) const
|
||||
nano::error nano::opencl_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
tree_a.put ("platform", std::to_string (platform));
|
||||
tree_a.put ("device", std::to_string (device));
|
||||
tree_a.put ("threads", std::to_string (threads));
|
||||
json.put ("platform", platform);
|
||||
json.put ("device", device);
|
||||
json.put ("threads", threads);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano::opencl_config::deserialize_json (boost::property_tree::ptree const & tree_a)
|
||||
nano::error nano::opencl_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
auto result (false);
|
||||
try
|
||||
{
|
||||
auto platform_l (tree_a.get<std::string> ("platform"));
|
||||
auto device_l (tree_a.get<std::string> ("device"));
|
||||
auto threads_l (tree_a.get<std::string> ("threads"));
|
||||
try
|
||||
{
|
||||
platform = std::stoull (platform_l);
|
||||
device = std::stoull (device_l);
|
||||
threads = std::stoull (threads_l);
|
||||
}
|
||||
catch (std::logic_error const &)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
json.get_optional<unsigned> ("platform", platform);
|
||||
json.get_optional<unsigned> ("device", device);
|
||||
json.get_optional<unsigned> ("threads", threads);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::opencl_work::opencl_work (bool & error_a, nano::opencl_config const & config_a, nano::opencl_environment & environment_a, nano::logging & logging_a) :
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/node/xorshift.hpp>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/xorshift.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
|
@ -39,8 +40,8 @@ class opencl_config
|
|||
public:
|
||||
opencl_config ();
|
||||
opencl_config (unsigned, unsigned, unsigned);
|
||||
void serialize_json (boost::property_tree::ptree &) const;
|
||||
bool deserialize_json (boost::property_tree::ptree const &);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (nano::jsonconfig &);
|
||||
unsigned platform;
|
||||
unsigned device;
|
||||
unsigned threads;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#include <boost/algorithm/string.hpp>
|
||||
#include <nano/node/rpc.hpp>
|
||||
|
||||
#include <nano/lib/interface.h>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/rpc.hpp>
|
||||
|
||||
#ifdef NANO_SECURE_RPC
|
||||
#include <nano/node/rpc_secure.hpp>
|
||||
|
|
@ -16,35 +15,28 @@ verbose_logging (false)
|
|||
{
|
||||
}
|
||||
|
||||
void nano::rpc_secure_config::serialize_json (boost::property_tree::ptree & tree_a) const
|
||||
nano::error nano::rpc_secure_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
tree_a.put ("enable", enable);
|
||||
tree_a.put ("verbose_logging", verbose_logging);
|
||||
tree_a.put ("server_key_passphrase", server_key_passphrase);
|
||||
tree_a.put ("server_cert_path", server_cert_path);
|
||||
tree_a.put ("server_key_path", server_key_path);
|
||||
tree_a.put ("server_dh_path", server_dh_path);
|
||||
tree_a.put ("client_certs_path", client_certs_path);
|
||||
json.put ("enable", enable);
|
||||
json.put ("verbose_logging", verbose_logging);
|
||||
json.put ("server_key_passphrase", server_key_passphrase);
|
||||
json.put ("server_cert_path", server_cert_path);
|
||||
json.put ("server_key_path", server_key_path);
|
||||
json.put ("server_dh_path", server_dh_path);
|
||||
json.put ("client_certs_path", client_certs_path);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano::rpc_secure_config::deserialize_json (boost::property_tree::ptree const & tree_a)
|
||||
nano::error nano::rpc_secure_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
auto error (false);
|
||||
try
|
||||
{
|
||||
enable = tree_a.get<bool> ("enable");
|
||||
verbose_logging = tree_a.get<bool> ("verbose_logging");
|
||||
server_key_passphrase = tree_a.get<std::string> ("server_key_passphrase");
|
||||
server_cert_path = tree_a.get<std::string> ("server_cert_path");
|
||||
server_key_path = tree_a.get<std::string> ("server_key_path");
|
||||
server_dh_path = tree_a.get<std::string> ("server_dh_path");
|
||||
client_certs_path = tree_a.get<std::string> ("client_certs_path");
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
return error;
|
||||
json.get_required<bool> ("enable", enable);
|
||||
json.get_required<bool> ("verbose_logging", verbose_logging);
|
||||
json.get_required<std::string> ("server_key_passphrase", server_key_passphrase);
|
||||
json.get_required<std::string> ("server_cert_path", server_cert_path);
|
||||
json.get_required<std::string> ("server_key_path", server_key_path);
|
||||
json.get_required<std::string> ("server_dh_path", server_dh_path);
|
||||
json.get_required<std::string> ("client_certs_path", client_certs_path);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::rpc_config::rpc_config () :
|
||||
|
|
@ -67,59 +59,33 @@ max_json_depth (20)
|
|||
{
|
||||
}
|
||||
|
||||
void nano::rpc_config::serialize_json (boost::property_tree::ptree & tree_a) const
|
||||
nano::error nano::rpc_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
tree_a.put ("address", address.to_string ());
|
||||
tree_a.put ("port", std::to_string (port));
|
||||
tree_a.put ("enable_control", enable_control);
|
||||
tree_a.put ("frontier_request_limit", frontier_request_limit);
|
||||
tree_a.put ("chain_request_limit", chain_request_limit);
|
||||
tree_a.put ("max_json_depth", max_json_depth);
|
||||
json.put ("address", address.to_string ());
|
||||
json.put ("port", port);
|
||||
json.put ("enable_control", enable_control);
|
||||
json.put ("frontier_request_limit", frontier_request_limit);
|
||||
json.put ("chain_request_limit", chain_request_limit);
|
||||
json.put ("max_json_depth", max_json_depth);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
bool nano::rpc_config::deserialize_json (boost::property_tree::ptree const & tree_a)
|
||||
nano::error nano::rpc_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
auto result (false);
|
||||
try
|
||||
boost::optional<nano::jsonconfig> rpc_secure_l;
|
||||
json.get_optional_child ("secure", rpc_secure_l);
|
||||
if (rpc_secure_l)
|
||||
{
|
||||
auto rpc_secure_l (tree_a.get_child_optional ("secure"));
|
||||
if (rpc_secure_l)
|
||||
{
|
||||
result = secure.deserialize_json (rpc_secure_l.get ());
|
||||
}
|
||||
secure.deserialize_json (*rpc_secure_l);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
auto address_l (tree_a.get<std::string> ("address"));
|
||||
auto port_l (tree_a.get<std::string> ("port"));
|
||||
enable_control = tree_a.get<bool> ("enable_control");
|
||||
auto frontier_request_limit_l (tree_a.get<std::string> ("frontier_request_limit"));
|
||||
auto chain_request_limit_l (tree_a.get<std::string> ("chain_request_limit"));
|
||||
max_json_depth = tree_a.get<uint8_t> ("max_json_depth", max_json_depth);
|
||||
try
|
||||
{
|
||||
port = std::stoul (port_l);
|
||||
result = port > std::numeric_limits<uint16_t>::max ();
|
||||
frontier_request_limit = std::stoull (frontier_request_limit_l);
|
||||
chain_request_limit = std::stoull (chain_request_limit_l);
|
||||
}
|
||||
catch (std::logic_error const &)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
address = boost::asio::ip::address_v6::from_string (address_l, ec);
|
||||
if (ec)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
json.get_required<boost::asio::ip::address_v6> ("address", address);
|
||||
json.get_optional<uint16_t> ("port", port);
|
||||
json.get_optional<bool> ("enable_control", enable_control);
|
||||
json.get_optional<uint64_t> ("frontier_request_limit", frontier_request_limit);
|
||||
json.get_optional<uint64_t> ("chain_request_limit", chain_request_limit);
|
||||
json.get_optional<uint8_t> ("max_json_depth", max_json_depth);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::rpc::rpc (boost::asio::io_context & io_ctx_a, nano::node & node_a, nano::rpc_config const & config_a) :
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <boost/beast.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
@ -17,8 +19,8 @@ class rpc_secure_config
|
|||
{
|
||||
public:
|
||||
rpc_secure_config ();
|
||||
void serialize_json (boost::property_tree::ptree &) const;
|
||||
bool deserialize_json (boost::property_tree::ptree const &);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (nano::jsonconfig &);
|
||||
|
||||
/** If true, enable TLS */
|
||||
bool enable;
|
||||
|
|
@ -40,8 +42,8 @@ class rpc_config
|
|||
public:
|
||||
rpc_config ();
|
||||
rpc_config (bool);
|
||||
void serialize_json (boost::property_tree::ptree &) const;
|
||||
bool deserialize_json (boost::property_tree::ptree const &);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (nano::jsonconfig &);
|
||||
boost::asio::ip::address_v6 address;
|
||||
uint16_t port;
|
||||
bool enable_control;
|
||||
|
|
|
|||
|
|
@ -9,33 +9,34 @@
|
|||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
||||
bool nano::stat_config::deserialize_json (boost::property_tree::ptree & tree_a)
|
||||
nano::error nano::stat_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
auto sampling_l (tree_a.get_child_optional ("sampling"));
|
||||
auto sampling_l (json.get_optional_child ("sampling"));
|
||||
if (sampling_l)
|
||||
{
|
||||
sampling_enabled = sampling_l->get<bool> ("enabled", sampling_enabled);
|
||||
capacity = sampling_l->get<size_t> ("capacity", capacity);
|
||||
interval = sampling_l->get<size_t> ("interval", interval);
|
||||
sampling_l->get<bool> ("enabled", sampling_enabled);
|
||||
sampling_l->get<size_t> ("capacity", capacity);
|
||||
sampling_l->get<size_t> ("interval", interval);
|
||||
}
|
||||
|
||||
auto log_l (tree_a.get_child_optional ("log"));
|
||||
auto log_l (json.get_optional_child ("log"));
|
||||
if (log_l)
|
||||
{
|
||||
log_headers = log_l->get<bool> ("headers", log_headers);
|
||||
log_interval_counters = log_l->get<size_t> ("interval_counters", log_interval_counters);
|
||||
log_interval_samples = log_l->get<size_t> ("interval_samples", log_interval_samples);
|
||||
log_rotation_count = log_l->get<size_t> ("rotation_count", log_rotation_count);
|
||||
log_counters_filename = log_l->get<std::string> ("filename_counters", log_counters_filename);
|
||||
log_samples_filename = log_l->get<std::string> ("filename_samples", log_samples_filename);
|
||||
log_l->get<bool> ("headers", log_headers);
|
||||
log_l->get<size_t> ("interval_counters", log_interval_counters);
|
||||
log_l->get<size_t> ("interval_samples", log_interval_samples);
|
||||
log_l->get<size_t> ("rotation_count", log_rotation_count);
|
||||
log_l->get<std::string> ("filename_counters", log_counters_filename);
|
||||
log_l->get<std::string> ("filename_samples", log_samples_filename);
|
||||
|
||||
// Don't allow specifying the same file name for counter and samples logs
|
||||
error = (log_counters_filename == log_samples_filename);
|
||||
if (log_counters_filename == log_samples_filename)
|
||||
{
|
||||
json.get_error ().set ("The statistics counter and samples config values must be different");
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
std::string nano::stat_log_sink::tm_to_string (tm & tm)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
|
@ -23,7 +25,7 @@ class stat_config
|
|||
{
|
||||
public:
|
||||
/** Reads the JSON statistics node */
|
||||
bool deserialize_json (boost::property_tree::ptree & tree_a);
|
||||
nano::error deserialize_json (nano::jsonconfig & json);
|
||||
|
||||
/** If true, sampling of counters is enabled */
|
||||
bool sampling_enabled{ false };
|
||||
|
|
|
|||
|
|
@ -109,14 +109,3 @@ std::vector<boost::filesystem::path> nano::remove_temporary_directories ()
|
|||
}
|
||||
return all_unique_paths;
|
||||
}
|
||||
|
||||
void nano::open_or_create (std::fstream & stream_a, std::string const & path_a)
|
||||
{
|
||||
stream_a.open (path_a, std::ios_base::in);
|
||||
if (stream_a.fail ())
|
||||
{
|
||||
stream_a.open (path_a, std::ios_base::out);
|
||||
}
|
||||
stream_a.close ();
|
||||
stream_a.open (path_a, std::ios_base::in | std::ios_base::out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <cryptopp/osrng.h>
|
||||
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/interface.h>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
|
||||
|
|
@ -29,81 +30,4 @@ bool migrate_working_path (std::string &);
|
|||
boost::filesystem::path unique_path ();
|
||||
// Remove all unique tmp directories created by the process. The list of unique paths are returned.
|
||||
std::vector<boost::filesystem::path> remove_temporary_directories ();
|
||||
// C++ stream are absolutely horrible so I need this helper function to do the most basic operation of creating a file if it doesn't exist or truncating it.
|
||||
void open_or_create (std::fstream &, std::string const &);
|
||||
// Reads a json object from the stream and if was changed, write the object back to the stream
|
||||
template <typename T>
|
||||
bool fetch_object (T & object, std::iostream & stream_a)
|
||||
{
|
||||
assert (stream_a.tellg () == std::streampos (0) || stream_a.tellg () == std::streampos (-1));
|
||||
assert (stream_a.tellp () == std::streampos (0) || stream_a.tellp () == std::streampos (-1));
|
||||
bool error (false);
|
||||
boost::property_tree::ptree tree;
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_json (stream_a, tree);
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
auto pos (stream_a.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
if (!error)
|
||||
{
|
||||
auto updated (false);
|
||||
error = object.deserialize_json (updated, tree);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
// Reads a json object from the stream and if was changed, write the object back to the stream
|
||||
template <typename T>
|
||||
bool fetch_object (T & object, boost::filesystem::path const & path_a)
|
||||
{
|
||||
bool error (false);
|
||||
std::fstream config_file;
|
||||
nano::open_or_create (config_file, path_a.string ());
|
||||
|
||||
if (!config_file.fail ())
|
||||
{
|
||||
boost::property_tree::ptree tree;
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_json (config_file, tree);
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
auto pos (config_file.tellg ());
|
||||
if (pos != std::streampos (0))
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
config_file.close ();
|
||||
|
||||
if (!error)
|
||||
{
|
||||
auto updated (false);
|
||||
error = object.deserialize_json (updated, tree);
|
||||
if (!error && updated)
|
||||
{
|
||||
config_file.open (path_a.string (), std::ios_base::out | std::ios_base::trunc);
|
||||
try
|
||||
{
|
||||
boost::property_tree::write_json (config_file, tree);
|
||||
}
|
||||
catch (std::runtime_error const &)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
config_file.close ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue