BasicConfig support for legacy values:

* A legacy value is a config section with a single-line.
* These values may be read from the BasicConfig interface so
  the deprecated Config class does not need to be exposed to
  clients.
* Made Config class more testable.
This commit is contained in:
seelabs
2015-02-03 12:03:39 -08:00
committed by Tom Ritchford
parent b11ad375cd
commit 617d84c0ef
13 changed files with 691 additions and 317 deletions

View File

@@ -1926,6 +1926,9 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\core\LoadMonitor.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\core\tests\Config.test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\core\tests\LoadFeeTrack.test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>

View File

@@ -2844,6 +2844,9 @@
<ClInclude Include="..\..\src\ripple\core\LoadMonitor.h">
<Filter>ripple\core</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\core\tests\Config.test.cpp">
<Filter>ripple\core\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\core\tests\LoadFeeTrack.test.cpp">
<Filter>ripple\core\tests</Filter>
</ClCompile>

View File

@@ -698,7 +698,8 @@
# There are 4 book-keeping SQLite database that the server creates and
# maintains. If you omit this configuration setting, it will default to
# creating a directory called "db" located in the same place as your
# rippled.cfg file.
# rippled.cfg file. Partial pathnames will be considered relative to
# the location of the rippled executable.
#
#
#

View File

@@ -58,7 +58,7 @@ setup_DatabaseCon (Config const& c)
setup.onlineDelete = c.nodeDatabase["online_delete"].getIntValue();
setup.startUp = c.START_UP;
setup.standAlone = c.RUN_STANDALONE;
setup.dataDir = c.DATA_DIR;
setup.dataDir = c.legacy ("database_path");
return setup;
}

View File

@@ -887,7 +887,8 @@ public:
{
// VFALCO TODO Move all this into doSweep
boost::filesystem::space_info space = boost::filesystem::space (getConfig ().DATA_DIR);
boost::filesystem::space_info space =
boost::filesystem::space (getConfig ().legacy ("database_path"));
// VFALCO TODO Give this magic constant a name and move it into a well documented header
//

View File

@@ -700,7 +700,7 @@ setup_SHAMapStore (Config const& c)
setup.ledgerHistory = c.LEDGER_HISTORY;
setup.nodeDatabase = c.nodeDatabase;
setup.ephemeralNodeDatabase = c.ephemeralNodeDatabase;
setup.databasePath = c.DATABASE_PATH;
setup.databasePath = c.legacy("database_path");
if (c.nodeDatabase["delete_batch"].isNotEmpty())
setup.deleteBatch = c.nodeDatabase["delete_batch"].getIntValue();
if (c.nodeDatabase["backOff"].isNotEmpty())

View File

@@ -76,6 +76,38 @@ public:
return values_;
}
/**
* Set the legacy value for this section.
*/
void
legacy (std::string value)
{
if (lines_.empty ())
lines_.emplace_back (std::move (value));
else
{
assert (lines_.size () == 1);
lines_[0] = std::move (value);
}
}
/**
* Get the legacy value for this section.
*
* @return The retrieved value. A section with an empty legacy value returns
an empty string.
*/
std::string
legacy () const
{
if (lines_.empty ())
return "";
else if (lines_.size () > 1)
throw std::runtime_error (
"A legacy value must have exactly one line. Section: " + name_);
return lines_[0];
}
/** Set a key/value pair.
The previous value is discarded.
*/
@@ -150,6 +182,29 @@ public:
overwrite (std::string const& section, std::string const& key,
std::string const& value);
/**
* Set a value that is not a key/value pair.
*
* The value is stored as the section's first value and may be retrieved
* through section::legacy.
*
* @param section Name of the section to modify.
* @param value Contents of the legacy value.
*/
void
legacy(std::string const& section, std::string value);
/**
* Get the legacy value of a section. A section with a
* single-line value may be retrieved as a legacy value.
*
* @param sectionName Retrieve the contents of this section's
* legacy value.
* @returun Contents of the legacy value.
*/
std::string
legacy(std::string const& sectionName) const;
friend
std::ostream&
operator<< (std::ostream& ss, BasicConfig const& c);
@@ -157,15 +212,6 @@ public:
protected:
void
build (IniFileSections const& ifs);
/** Insert a legacy single section as a key/value pair.
Does nothing if the section does not exist, or does not contain
a single line that is not a key/value pair.
@deprecated
*/
void
remap (std::string const& legacy_section,
std::string const& key, std::string const& new_section);
};
//------------------------------------------------------------------------------

View File

@@ -106,24 +106,6 @@ BasicConfig::section (std::string const& name) const
return iter->second;
}
void
BasicConfig::remap (std::string const& legacy_section,
std::string const& key, std::string const& new_section)
{
auto const iter = map_.find (legacy_section);
if (iter == map_.end())
return;
if (iter->second.size() != 0)
return;
if (iter->second.lines().size() != 1)
return;
auto result = map_.emplace(std::piecewise_construct,
std::make_tuple(new_section), std::make_tuple(new_section));
auto& s = result.first->second;
s.append (iter->second.lines().front());
s.set (key, iter->second.lines().front());
}
void
BasicConfig::overwrite (std::string const& section, std::string const& key,
std::string const& value)
@@ -133,6 +115,18 @@ BasicConfig::overwrite (std::string const& section, std::string const& key,
result.first->second.set (key, value);
}
void
BasicConfig::legacy(std::string const& section, std::string value)
{
map_[section].legacy(std::move(value));
}
std::string
BasicConfig::legacy(std::string const& sectionName) const
{
return section (sectionName).legacy ();
}
void
BasicConfig::build (IniFileSections const& ifs)
{

View File

@@ -87,10 +87,10 @@ struct SizedItem
int sizes[5];
};
// VFALCO NOTE This entire derived class is deprecated
// For new config information use the style implied
// in the base class. For existing config information
// try to refactor code to use the new style.
// This entire derived class is deprecated.
// For new config information use the style implied
// in the base class. For existing config information
// try to refactor code to use the new style.
//
class Config : public BasicConfig
{
@@ -121,20 +121,17 @@ public:
/** Returns the directory from which the configuration file was loaded. */
beast::File getConfigDir () const;
/** Returns the directory in which the current database files are located. */
beast::File getDatabaseDir () const;
/** Returns the full path and filename of the debug log file. */
boost::filesystem::path getDebugLogFile () const;
// LEGACY FIELDS, REMOVE ASAP
// DEPRECATED
boost::filesystem::path CONFIG_FILE; // used by UniqueNodeList
private:
boost::filesystem::path CONFIG_DIR;
boost::filesystem::path DEBUG_LOGFILE;
void load ();
public:
// VFALCO TODO Make this private and fix callers to go through getDatabaseDir()
boost::filesystem::path DATA_DIR;
//--------------------------------------------------------------------------
@@ -152,10 +149,6 @@ public:
/** List of Validators entries from rippled.cfg */
std::vector <std::string> validators;
private:
/** The folder where new module databases should be located */
beast::File m_moduleDbPath;
public:
//--------------------------------------------------------------------------
/** Returns the location were databases should be located
@@ -164,7 +157,7 @@ public:
stored in a file named after the module (e.g. "peerfinder.sqlite") that
is inside that directory.
*/
beast::File const& getModuleDatabasePath ();
beast::File getModuleDatabasePath () const;
//--------------------------------------------------------------------------
@@ -234,9 +227,6 @@ public:
std::string START_LEDGER;
// Database
std::string DATABASE_PATH;
// Network parameters
int TRANSACTION_FEE_BASE; // The number of fee units a reference transaction costs
@@ -312,10 +302,16 @@ public:
int getSize (SizedItemName) const;
void setup (std::string const& strConf, bool bQuiet);
void load ();
/**
* Load the conig from the contents of the sting.
*
* @param fileContents String representing the config contents.
*/
void loadFromString (std::string const& fileContents);
};
// VFALCO DEPRECATED
// DEPRECATED
extern Config& getConfig();
} // ripple

View File

@@ -34,7 +34,6 @@ struct ConfigSection
#define SECTION_ACCOUNT_PROBE_MAX "account_probe_max"
#define SECTION_AMENDMENTS "amendments"
#define SECTION_CLUSTER_NODES "cluster_nodes"
#define SECTION_DATABASE_PATH "database_path"
#define SECTION_DEBUG_LOGFILE "debug_logfile"
#define SECTION_ELB_SUPPORT "elb_support"
#define SECTION_FEE_DEFAULT "fee_default"

View File

@@ -284,6 +284,7 @@ getEnvVar (char const* name)
void Config::setup (std::string const& strConf, bool bQuiet)
{
boost::filesystem::path dataDir;
boost::system::error_code ec;
std::string strDbPath, strConfFile;
@@ -309,13 +310,13 @@ void Config::setup (std::string const& strConf, bool bQuiet)
CONFIG_FILE = strConfFile;
CONFIG_DIR = boost::filesystem::absolute (CONFIG_FILE);
CONFIG_DIR.remove_filename ();
DATA_DIR = CONFIG_DIR / strDbPath;
dataDir = CONFIG_DIR / strDbPath;
}
else
{
CONFIG_DIR = boost::filesystem::current_path ();
CONFIG_FILE = CONFIG_DIR / strConfFile;
DATA_DIR = CONFIG_DIR / strDbPath;
dataDir = CONFIG_DIR / strDbPath;
// Construct XDG config and data home.
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
@@ -345,7 +346,7 @@ void Config::setup (std::string const& strConf, bool bQuiet)
CONFIG_DIR = strXdgConfigHome + "/" + systemName ();
CONFIG_FILE = CONFIG_DIR / strConfFile;
DATA_DIR = strXdgDataHome + "/" + systemName ();
dataDir = strXdgDataHome + "/" + systemName ();
boost::filesystem::create_directories (CONFIG_DIR, ec);
@@ -358,274 +359,257 @@ void Config::setup (std::string const& strConf, bool bQuiet)
// Update default values
load ();
{
// load() may have set a new value for the dataDir
std::string const dbPath (legacy ("database_path"));
if (!dbPath.empty ())
{
dataDir = boost::filesystem::path (dbPath);
}
}
boost::filesystem::create_directories (DATA_DIR, ec);
boost::filesystem::create_directories (dataDir, ec);
if (ec)
throw std::runtime_error (boost::str (boost::format ("Can not create %s") % DATA_DIR));
throw std::runtime_error (
boost::str (boost::format ("Can not create %s") % dataDir));
// Create the new unified database
m_moduleDbPath = getDatabaseDir();
// This code is temporarily disabled, and modules will fall back to using
// per-module databases (e.g. "peerfinder.sqlite") under the module db path
//
//if (m_moduleDbPath.isDirectory ())
// m_moduleDbPath = m_moduleDbPath.getChildFile("rippled.sqlite");
legacy ("database_path", boost::filesystem::absolute (dataDir).string ());
}
void Config::load ()
{
if (!QUIET)
std::cerr << "Loading: " << CONFIG_FILE << std::endl;
std::cerr << "Loading: " << CONFIG_FILE << "\n";
std::ifstream ifsConfig (CONFIG_FILE.c_str (), std::ios::in);
std::ifstream ifsConfig (CONFIG_FILE.c_str (), std::ios::in);
if (!ifsConfig)
{
std::cerr << "Failed to open '" << CONFIG_FILE << "'." << std::endl;
return;
}
else
{
std::string file_contents;
file_contents.assign ((std::istreambuf_iterator<char> (ifsConfig)),
std::istreambuf_iterator<char> ());
if (ifsConfig.bad ())
std::string fileContents;
fileContents.assign ((std::istreambuf_iterator<char>(ifsConfig)),
std::istreambuf_iterator<char>());
if (ifsConfig.bad ())
{
std::cerr << "Failed to read '" << CONFIG_FILE << "'." << std::endl;
return;
}
loadFromString (fileContents);
}
void Config::loadFromString (std::string const& fileContents)
{
IniFileSections secConfig = parseIniFile (fileContents, true);
build (secConfig);
if (auto s = getIniFileSection (secConfig, SECTION_VALIDATORS))
validators = *s;
if (auto s = getIniFileSection (secConfig, SECTION_CLUSTER_NODES))
CLUSTER_NODES = *s;
if (auto s = getIniFileSection (secConfig, SECTION_IPS))
IPS = *s;
if (auto s = getIniFileSection (secConfig, SECTION_IPS_FIXED))
IPS_FIXED = *s;
if (auto s = getIniFileSection (secConfig, SECTION_SNTP))
SNTP_SERVERS = *s;
if (auto s = getIniFileSection (secConfig, SECTION_RPC_STARTUP))
{
RPC_STARTUP = Json::arrayValue;
for (auto const& strJson : *s)
{
std::cerr << "Failed to read '" << CONFIG_FILE << "'." << std::endl;
Json::Reader jrReader;
Json::Value jvCommand;
if (!jrReader.parse (strJson, jvCommand))
throw std::runtime_error (
boost::str (boost::format (
"Couldn't parse [" SECTION_RPC_STARTUP "] command: %s") % strJson));
RPC_STARTUP.append (jvCommand);
}
}
{
std::string dbPath;
if (getSingleSection (secConfig, "database_path", dbPath))
{
boost::filesystem::path p(dbPath);
legacy("database_path",
boost::filesystem::absolute (p).string ());
}
}
(void) getSingleSection (secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE);
std::string strTemp;
if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp))
PEER_PRIVATE = beast::lexicalCastThrow <bool> (strTemp);
if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp))
PEERS_MAX = beast::lexicalCastThrow <int> (strTemp);
if (auto s = getIniFileSection (secConfig, SECTION_RPC_ADMIN_ALLOW))
{
std::vector<beast::IP::Endpoint> parsedAddresses;
parseAddresses (parsedAddresses, (*s).cbegin(), (*s).cend());
RPC_ADMIN_ALLOW.insert (RPC_ADMIN_ALLOW.end(),
parsedAddresses.cbegin (), parsedAddresses.cend ());
}
insightSettings = parseKeyValueSection (secConfig, SECTION_INSIGHT);
nodeDatabase = parseKeyValueSection (
secConfig, ConfigSection::nodeDatabase ());
ephemeralNodeDatabase = parseKeyValueSection (
secConfig, ConfigSection::tempNodeDatabase ());
importNodeDatabase = parseKeyValueSection (
secConfig, ConfigSection::importNodeDatabase ());
if (getSingleSection (secConfig, SECTION_NODE_SIZE, strTemp))
{
if (strTemp == "tiny")
NODE_SIZE = 0;
else if (strTemp == "small")
NODE_SIZE = 1;
else if (strTemp == "medium")
NODE_SIZE = 2;
else if (strTemp == "large")
NODE_SIZE = 3;
else if (strTemp == "huge")
NODE_SIZE = 4;
else
{
IniFileSections secConfig = parseIniFile (file_contents, true);
std::string strTemp;
NODE_SIZE = beast::lexicalCastThrow <int> (strTemp);
build (secConfig);
// XXX Leak
IniFileSections::mapped_type* smtTmp;
smtTmp = getIniFileSection (secConfig, SECTION_VALIDATORS);
if (smtTmp)
{
validators = *smtTmp;
}
smtTmp = getIniFileSection (secConfig, SECTION_CLUSTER_NODES);
if (smtTmp)
{
CLUSTER_NODES = *smtTmp;
}
smtTmp = getIniFileSection (secConfig, SECTION_IPS);
if (smtTmp)
{
IPS = *smtTmp;
}
smtTmp = getIniFileSection (secConfig, SECTION_IPS_FIXED);
if (smtTmp)
{
IPS_FIXED = *smtTmp;
}
smtTmp = getIniFileSection (secConfig, SECTION_SNTP);
if (smtTmp)
{
SNTP_SERVERS = *smtTmp;
}
smtTmp = getIniFileSection (secConfig, SECTION_RPC_STARTUP);
if (smtTmp)
{
RPC_STARTUP = Json::arrayValue;
for (auto const& strJson : *smtTmp)
{
Json::Reader jrReader;
Json::Value jvCommand;
if (!jrReader.parse (strJson, jvCommand))
throw std::runtime_error (
boost::str (boost::format (
"Couldn't parse [" SECTION_RPC_STARTUP "] command: %s") % strJson));
RPC_STARTUP.append (jvCommand);
}
}
if (getSingleSection (secConfig, SECTION_DATABASE_PATH, DATABASE_PATH))
DATA_DIR = DATABASE_PATH;
(void) getSingleSection (secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE);
if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp))
PEER_PRIVATE = beast::lexicalCastThrow <bool> (strTemp);
if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp))
PEERS_MAX = beast::lexicalCastThrow <int> (strTemp);
smtTmp = getIniFileSection (secConfig, SECTION_RPC_ADMIN_ALLOW);
if (smtTmp)
{
std::vector<beast::IP::Endpoint> parsedAddresses;
//parseAddresses<std::vector<beast::IP::Endpoint>, std::vector<std::string>::const_iterator>
// (parsedAddresses, (*smtTmp).cbegin(), (*smtTmp).cend());
parseAddresses (parsedAddresses, (*smtTmp).cbegin(), (*smtTmp).cend());
RPC_ADMIN_ALLOW.insert (RPC_ADMIN_ALLOW.end(),
parsedAddresses.cbegin (), parsedAddresses.cend ());
}
insightSettings = parseKeyValueSection (secConfig, SECTION_INSIGHT);
nodeDatabase = parseKeyValueSection (
secConfig, ConfigSection::nodeDatabase ());
ephemeralNodeDatabase = parseKeyValueSection (
secConfig, ConfigSection::tempNodeDatabase ());
importNodeDatabase = parseKeyValueSection (
secConfig, ConfigSection::importNodeDatabase ());
if (getSingleSection (secConfig, SECTION_NODE_SIZE, strTemp))
{
if (strTemp == "tiny")
NODE_SIZE = 0;
else if (strTemp == "small")
NODE_SIZE = 1;
else if (strTemp == "medium")
NODE_SIZE = 2;
else if (strTemp == "large")
NODE_SIZE = 3;
else if (strTemp == "huge")
NODE_SIZE = 4;
else
{
NODE_SIZE = beast::lexicalCastThrow <int> (strTemp);
if (NODE_SIZE < 0)
NODE_SIZE = 0;
else if (NODE_SIZE > 4)
NODE_SIZE = 4;
}
}
if (getSingleSection (secConfig, SECTION_ELB_SUPPORT, strTemp))
ELB_SUPPORT = beast::lexicalCastThrow <bool> (strTemp);
if (getSingleSection (secConfig, SECTION_WEBSOCKET_PING_FREQ, strTemp))
WEBSOCKET_PING_FREQ = beast::lexicalCastThrow <int> (strTemp);
getSingleSection (secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE);
getSingleSection (secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR);
if (getSingleSection (secConfig, SECTION_SSL_VERIFY, strTemp))
SSL_VERIFY = beast::lexicalCastThrow <bool> (strTemp);
if (getSingleSection (secConfig, SECTION_VALIDATION_SEED, strTemp))
{
VALIDATION_SEED.setSeedGeneric (strTemp);
if (VALIDATION_SEED.isValid ())
{
VALIDATION_PUB = RippleAddress::createNodePublic (VALIDATION_SEED);
VALIDATION_PRIV = RippleAddress::createNodePrivate (VALIDATION_SEED);
}
}
if (getSingleSection (secConfig, SECTION_NODE_SEED, strTemp))
{
NODE_SEED.setSeedGeneric (strTemp);
if (NODE_SEED.isValid ())
{
NODE_PUB = RippleAddress::createNodePublic (NODE_SEED);
NODE_PRIV = RippleAddress::createNodePrivate (NODE_SEED);
}
}
if (getSingleSection (secConfig, SECTION_NETWORK_QUORUM, strTemp))
NETWORK_QUORUM = beast::lexicalCastThrow <std::size_t> (strTemp);
if (getSingleSection (secConfig, SECTION_VALIDATION_QUORUM, strTemp))
VALIDATION_QUORUM = std::max (0, beast::lexicalCastThrow <int> (strTemp));
if (getSingleSection (secConfig, SECTION_FEE_ACCOUNT_RESERVE, strTemp))
FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow <std::uint64_t> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_OWNER_RESERVE, strTemp))
FEE_OWNER_RESERVE = beast::lexicalCastThrow <std::uint64_t> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_OFFER, strTemp))
FEE_OFFER = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_DEFAULT, strTemp))
FEE_DEFAULT = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_OPERATION, strTemp))
FEE_CONTRACT_OPERATION = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_LEDGER_HISTORY, strTemp))
{
boost::to_lower (strTemp);
if (strTemp == "full")
LEDGER_HISTORY = 1000000000u;
else if (strTemp == "none")
LEDGER_HISTORY = 0;
else
LEDGER_HISTORY = beast::lexicalCastThrow <std::uint32_t> (strTemp);
}
if (getSingleSection (secConfig, SECTION_FETCH_DEPTH, strTemp))
{
boost::to_lower (strTemp);
if (strTemp == "none")
FETCH_DEPTH = 0;
else if (strTemp == "full")
FETCH_DEPTH = 1000000000u;
else
FETCH_DEPTH = beast::lexicalCastThrow <std::uint32_t> (strTemp);
if (FETCH_DEPTH < 10)
FETCH_DEPTH = 10;
}
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_OLD, strTemp))
PATH_SEARCH_OLD = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_PATH_SEARCH, strTemp))
PATH_SEARCH = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_FAST, strTemp))
PATH_SEARCH_FAST = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_MAX, strTemp))
PATH_SEARCH_MAX = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp))
ACCOUNT_PROBE_MAX = beast::lexicalCastThrow <int> (strTemp);
(void) getSingleSection (secConfig, SECTION_SMS_FROM, SMS_FROM);
(void) getSingleSection (secConfig, SECTION_SMS_KEY, SMS_KEY);
(void) getSingleSection (secConfig, SECTION_SMS_SECRET, SMS_SECRET);
(void) getSingleSection (secConfig, SECTION_SMS_TO, SMS_TO);
(void) getSingleSection (secConfig, SECTION_SMS_URL, SMS_URL);
if (getSingleSection (secConfig, SECTION_VALIDATORS_FILE, strTemp))
{
VALIDATORS_FILE = strTemp;
}
if (getSingleSection (secConfig, SECTION_DEBUG_LOGFILE, strTemp))
DEBUG_LOGFILE = strTemp;
if (NODE_SIZE < 0)
NODE_SIZE = 0;
else if (NODE_SIZE > 4)
NODE_SIZE = 4;
}
}
if (getSingleSection (secConfig, SECTION_ELB_SUPPORT, strTemp))
ELB_SUPPORT = beast::lexicalCastThrow <bool> (strTemp);
if (getSingleSection (secConfig, SECTION_WEBSOCKET_PING_FREQ, strTemp))
WEBSOCKET_PING_FREQ = beast::lexicalCastThrow <int> (strTemp);
getSingleSection (secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE);
getSingleSection (secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR);
if (getSingleSection (secConfig, SECTION_SSL_VERIFY, strTemp))
SSL_VERIFY = beast::lexicalCastThrow <bool> (strTemp);
if (getSingleSection (secConfig, SECTION_VALIDATION_SEED, strTemp))
{
VALIDATION_SEED.setSeedGeneric (strTemp);
if (VALIDATION_SEED.isValid ())
{
VALIDATION_PUB = RippleAddress::createNodePublic (VALIDATION_SEED);
VALIDATION_PRIV = RippleAddress::createNodePrivate (VALIDATION_SEED);
}
}
if (getSingleSection (secConfig, SECTION_NODE_SEED, strTemp))
{
NODE_SEED.setSeedGeneric (strTemp);
if (NODE_SEED.isValid ())
{
NODE_PUB = RippleAddress::createNodePublic (NODE_SEED);
NODE_PRIV = RippleAddress::createNodePrivate (NODE_SEED);
}
}
if (getSingleSection (secConfig, SECTION_NETWORK_QUORUM, strTemp))
NETWORK_QUORUM = beast::lexicalCastThrow <std::size_t> (strTemp);
if (getSingleSection (secConfig, SECTION_VALIDATION_QUORUM, strTemp))
VALIDATION_QUORUM = std::max (0, beast::lexicalCastThrow <int> (strTemp));
if (getSingleSection (secConfig, SECTION_FEE_ACCOUNT_RESERVE, strTemp))
FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow <std::uint64_t> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_OWNER_RESERVE, strTemp))
FEE_OWNER_RESERVE = beast::lexicalCastThrow <std::uint64_t> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_OFFER, strTemp))
FEE_OFFER = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_DEFAULT, strTemp))
FEE_DEFAULT = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_FEE_OPERATION, strTemp))
FEE_CONTRACT_OPERATION = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_LEDGER_HISTORY, strTemp))
{
boost::to_lower (strTemp);
if (strTemp == "full")
LEDGER_HISTORY = 1000000000u;
else if (strTemp == "none")
LEDGER_HISTORY = 0;
else
LEDGER_HISTORY = beast::lexicalCastThrow <std::uint32_t> (strTemp);
}
if (getSingleSection (secConfig, SECTION_FETCH_DEPTH, strTemp))
{
boost::to_lower (strTemp);
if (strTemp == "none")
FETCH_DEPTH = 0;
else if (strTemp == "full")
FETCH_DEPTH = 1000000000u;
else
FETCH_DEPTH = beast::lexicalCastThrow <std::uint32_t> (strTemp);
if (FETCH_DEPTH < 10)
FETCH_DEPTH = 10;
}
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_OLD, strTemp))
PATH_SEARCH_OLD = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_PATH_SEARCH, strTemp))
PATH_SEARCH = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_FAST, strTemp))
PATH_SEARCH_FAST = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_PATH_SEARCH_MAX, strTemp))
PATH_SEARCH_MAX = beast::lexicalCastThrow <int> (strTemp);
if (getSingleSection (secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp))
ACCOUNT_PROBE_MAX = beast::lexicalCastThrow <int> (strTemp);
(void) getSingleSection (secConfig, SECTION_SMS_FROM, SMS_FROM);
(void) getSingleSection (secConfig, SECTION_SMS_KEY, SMS_KEY);
(void) getSingleSection (secConfig, SECTION_SMS_SECRET, SMS_SECRET);
(void) getSingleSection (secConfig, SECTION_SMS_TO, SMS_TO);
(void) getSingleSection (secConfig, SECTION_SMS_URL, SMS_URL);
if (getSingleSection (secConfig, SECTION_VALIDATORS_FILE, strTemp))
{
VALIDATORS_FILE = strTemp;
}
if (getSingleSection (secConfig, SECTION_DEBUG_LOGFILE, strTemp))
DEBUG_LOGFILE = strTemp;
}
int Config::getSize (SizedItemName item) const
@@ -702,19 +686,12 @@ boost::filesystem::path Config::getDebugLogFile () const
return log_file;
}
//------------------------------------------------------------------------------
//
// VFALCO NOTE Clean members area
//
Config& getConfig ()
{
static Config config;
return config;
}
//------------------------------------------------------------------------------
beast::File Config::getConfigDir () const
{
beast::String const s (CONFIG_FILE.native().c_str ());
@@ -723,14 +700,6 @@ beast::File Config::getConfigDir () const
return beast::File::nonexistent ();
}
beast::File Config::getDatabaseDir () const
{
beast::String const s (DATA_DIR.native().c_str());
if (s.isNotEmpty ())
return beast::File (s);
return beast::File::nonexistent ();
}
beast::File Config::getValidatorsFile () const
{
beast::String const s (VALIDATORS_FILE.native().c_str());
@@ -744,9 +713,14 @@ beast::URL Config::getValidatorsURL () const
return beast::parse_URL (VALIDATORS_SITE).second;
}
beast::File const& Config::getModuleDatabasePath ()
beast::File Config::getModuleDatabasePath () const
{
return m_moduleDbPath;
boost::filesystem::path dbPath (legacy ("database_path"));
beast::String const s (dbPath.native ().c_str ());
if (s.isNotEmpty ())
return beast::File (s);
return beast::File::nonexistent ();
}
} // ripple

View File

@@ -0,0 +1,356 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012-2015 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/core/impl/LoadFeeTrackImp.h>
#include <ripple/core/Config.h>
#include <ripple/basics/TestSuite.h>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <fstream>
#include <iostream>
namespace ripple {
namespace detail {
std::string configContents (std::string const& dbPath)
{
static boost::format configContentsTemplate (R"rippleConfig(
[server]
port_rpc
port_peer
port_wss_admin
[port_rpc]
port = 5005
ip = 127.0.0.1
admin = allow
protocol = https
[port_peer]
port = 51235
ip = 0.0.0.0
protocol = peer
[port_wss_admin]
port = 6006
ip = 127.0.0.1
admin = allow
protocol = wss
#[port_ws_public]
#port = 5005
#ip = 127.0.0.1
#protocol = wss
#-------------------------------------------------------------------------------
[node_size]
medium
# This is primary persistent datastore for rippled. This includes transaction
# metadata, account states, and ledger headers. Helpful information can be
# found here: https://ripple.com/wiki/NodeBackEnd
# delete old ledgers while maintaining at least 2000. Do not require an
# external administrative command to initiate deletion.
[node_db]
type=memory
path=/Users/dummy/ripple/config/db/rocksdb
open_files=2000
filter_bits=12
cache_mb=256
file_size_mb=8
file_size_mult=2
%1%
%2%
# This needs to be an absolute directory reference, not a relative one.
# Modify this value as required.
[debug_logfile]
/Users/dummy/ripple/config/log/debug.log
[sntp_servers]
time.windows.com
time.apple.com
time.nist.gov
pool.ntp.org
# Where to find some other servers speaking the Ripple protocol.
#
[ips]
r.ripple.com 51235
# The latest validators can be obtained from
# https://ripple.com/ripple.txt
#
[validators]
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
# Ditto.
[validation_quorum]
3
# Turn down default logging to save disk space in the long run.
# Valid values here are trace, debug, info, warning, error, and fatal
[rpc_startup]
{ "command": "log_level", "severity": "warning" }
# Defaults to 1 ("yes") so that certificates will be validated. To allow the use
# of self-signed certificates for development or internal use, set to 0 ("no").
[ssl_verify]
0
[sqdb]
backend=sqlite
)rippleConfig");
if (!dbPath.empty ())
return boost::str (configContentsTemplate % "[database_path]" % dbPath);
else
return boost::str (configContentsTemplate % "" % "");
}
/**
Write a config file and remove when done.
*/
class ConfigGuard
{
private:
using path = boost::filesystem::path;
path subDir_;
path configFile_;
path dataDir_;
bool rmSubDir_{false};
bool rmDataDir_{false};
Config config_;
public:
ConfigGuard (std::string subDir, std::string const& dbPath)
: subDir_ (std::move (subDir)), dataDir_ (dbPath)
{
using namespace boost::filesystem;
if (dbPath.empty ())
{
dataDir_ = subDir_ / path (Config::Helpers::getDatabaseDirName ());
}
configFile_ = subDir_ / path (Config::Helpers::getConfigFileName ());
{
if (!exists (subDir_))
{
create_directory (subDir_);
rmSubDir_ = true;
}
else if (is_directory (subDir_))
rmSubDir_ = false;
else
{
// Cannot run the test someone created a file where we want to
// put out directory
throw std::runtime_error ("Cannot create directory: " +
subDir_.string ());
}
}
if (!exists (configFile_))
{
std::ofstream o (configFile_.string ());
o << configContents (dbPath);
}
else
{
throw std::runtime_error (
"Refusing to overwrite existing config file: " +
configFile_.string ());
}
rmDataDir_ = !exists (dataDir_);
config_.setup (configFile_.string (), /*bQuiet*/ false);
}
Config& config ()
{
return config_;
}
bool dataDirExists () const
{
return boost::filesystem::is_directory (dataDir_);
}
bool configFileExists () const
{
return boost::filesystem::is_regular_file (configFile_);
}
~ConfigGuard ()
{
try
{
using namespace boost::filesystem;
if (!is_regular_file (configFile_))
std::cerr << "Expected " << configFile_.string ()
<< " to be an existing file.\n";
else
remove (configFile_.string ());
auto rmDir = [](path const& toRm)
{
if (is_directory (toRm) && is_empty (toRm))
remove (toRm);
else
std::cerr << "Expected " << toRm.string ()
<< " to be an empty existing directory.\n";
};
if (rmDataDir_)
rmDir (dataDir_);
else
std::cerr << "Skipping rm dir: " << dataDir_.string () << "\n";
if (rmSubDir_)
rmDir (subDir_);
else
std::cerr << "Skipping rm dir: " << subDir_.string () << "\n";
}
catch (std::exception& e)
{
// if we throw here, just let it die.
std::cerr << "Error in CreateConfigGuard: " << e.what () << "\n";
};
}
};
} // detail
class Config_test final : public TestSuite
{
private:
using path = boost::filesystem::path;
public:
void testLegacy ()
{
testcase ("legacy");
Config c;
std::string toLoad(R"rippleConfig(
[server]
port_rpc
port_peer
port_wss_admin
[ssl_verify]
0
[validation_quorum]
3
)rippleConfig");
c.loadFromString (toLoad);
expect (c.legacy ("ssl_verify") == "0");
expectException ([&c] {c.legacy ("server");}); // not a single line
// set a legacy value
expect (c.legacy ("not_in_file") == "");
c.legacy ("not_in_file", "new_value");
expect (c.legacy ("not_in_file") == "new_value");
}
void testDbPath ()
{
testcase ("database_path");
using namespace boost::filesystem;
{
boost::format cc ("[database_path]\n%1%\n");
auto const cwd = current_path ();
path const dataDirRel ("test_data_dir");
path const dataDirAbs (cwd / dataDirRel);
{
// Dummy test - do we get back what we put in
Config c;
c.loadFromString (boost::str (cc % dataDirAbs.string ()));
expect (c.legacy ("database_path") == dataDirAbs.string ());
}
{
// Rel paths should convert to abs paths
Config c;
c.loadFromString (boost::str (cc % dataDirRel.string ()));
expect (c.legacy ("database_path") == dataDirAbs.string ());
}
{
// No db sectcion.
// N.B. Config::setup will give database_path a default,
// load will not.
Config c;
c.loadFromString ("");
expect (c.legacy ("database_path") == "");
}
}
{
// read from file absolute path
auto const cwd = current_path ();
path const dataDirRel ("test_data_dir");
path const dataDirAbs (cwd / path ("test_db") / dataDirRel);
detail::ConfigGuard g ("test_db", dataDirAbs.string ());
auto& c (g.config ());
expect (g.dataDirExists ());
expect (g.configFileExists ());
expect (c.legacy ("database_path") == dataDirAbs.string (),
"dbPath Abs Path File");
}
{
// read from file relative path
std::string const dbPath ("my_db");
detail::ConfigGuard g ("test_db", dbPath);
auto& c (g.config ());
std::string const nativeDbPath = absolute (path (dbPath)).string ();
expect (g.dataDirExists ());
expect (g.configFileExists ());
expect (c.legacy ("database_path") == nativeDbPath,
"dbPath Rel Path File");
}
{
// read from file no path
detail::ConfigGuard g ("test_db", "");
auto& c (g.config ());
std::string const nativeDbPath =
absolute (path ("test_db") /
path (Config::Helpers::getDatabaseDirName ()))
.string ();
expect (g.dataDirExists ());
expect (g.configFileExists ());
expect (c.legacy ("database_path") == nativeDbPath,
"dbPath No Path");
}
}
void run ()
{
testLegacy ();
testDbPath ();
}
};
BEAST_DEFINE_TESTSUITE (Config, core, ripple);
} // ripple

View File

@@ -27,3 +27,4 @@
#include <ripple/core/impl/JobQueue.cpp>
#include <ripple/core/tests/LoadFeeTrack.test.cpp>
#include <ripple/core/tests/Config.test.cpp>