Add BasicConfig simplified config interface

This commit is contained in:
Vinnie Falco
2014-09-06 14:55:05 -07:00
parent c41ce469d0
commit 379e842080
2 changed files with 183 additions and 13 deletions

View File

@@ -20,6 +20,7 @@
#include <ripple/module/core/Config.h>
#include <ripple/module/core/ConfigSections.h>
#include <beast/module/core/text/LexicalCast.h>
#include <boost/regex.hpp>
namespace ripple {
@@ -205,6 +206,101 @@ parseAddresses (OutputSequence& out, InputIterator first, InputIterator last,
}
}
//------------------------------------------------------------------------------
//
// Section
//
//------------------------------------------------------------------------------
void
Section::append (std::vector <std::string> const& lines)
{
// <key> '=' <value>
static boost::regex const re1 (
"^" // start of line
"(?:\\s*)" // whitespace (optonal)
"([a-zA-Z][_a-zA-Z0-9]*)" // <key>
"(?:\\s*)" // whitespace (optional)
"(?:=)" // '='
"(?:\\s*)" // whitespace (optional)
"(.*\\S+)" // <value>
"(?:\\s*)" // whitespace (optional)
, boost::regex_constants::optimize
);
lines_.reserve (lines_.size() + lines.size());
for (auto const& line : lines)
{
boost::smatch match;
lines_.push_back (line);
if (boost::regex_match (line, match, re1))
{
auto const result = map_.emplace (
std::make_pair (match[1], match[2]));
#if 0
if (! result.second)
{
// If we decide on how to merge values we can do it here.
}
beast::debug_ostream log;
//log << "\"" << match[1] << "\" = \"" << match[2] << "\"";
#endif
}
}
}
bool
Section::exists (std::string const& name) const
{
return map_.find (name) != map_.end();
}
std::pair <std::string, bool>
Section::find (std::string const& name) const
{
auto const iter = map_.find (name);
if (iter == map_.end())
return {{}, false};
return {iter->second, true};
}
//------------------------------------------------------------------------------
//
// BasicConfig
//
//------------------------------------------------------------------------------
bool
BasicConfig::exists (std::string const& name) const
{
return map_.find (name) != map_.end();
}
Section const&
BasicConfig::section (std::string const& name) const
{
static Section none;
auto const iter = map_.find (name);
if (iter == map_.end())
return none;
return iter->second;
}
void
BasicConfig::build (IniFileSections const& ifs)
{
for (auto const& entry : ifs)
{
auto const result = map_.insert (std::make_pair (
entry.first, Section{}));
result.first->second.append (entry.second);
}
}
//------------------------------------------------------------------------------
//
// Config (DEPRECATED)
//
//------------------------------------------------------------------------------
Config::Config ()
@@ -322,7 +418,7 @@ void Config::setup (std::string const& strConf, bool bQuiet)
CONFIG_FILE = CONFIG_DIR / strConfFile;
DATA_DIR = CONFIG_DIR / strDbPath;
if (exists (CONFIG_FILE)
if (boost::filesystem::exists (CONFIG_FILE)
// Can we figure out XDG dirs?
|| (!getenv ("HOME") && (!getenv ("XDG_CONFIG_HOME") || !getenv ("XDG_DATA_HOME"))))
{
@@ -392,6 +488,7 @@ void Config::load ()
}
else
{
std::string file_contents;
file_contents.assign ((std::istreambuf_iterator<char> (ifsConfig)),
std::istreambuf_iterator<char> ());
@@ -404,6 +501,8 @@ void Config::load ()
IniFileSections secConfig = parseIniFile (file_contents, true);
std::string strTemp;
build (secConfig);
// XXX Leak
IniFileSections::mapped_type* smtTmp;
@@ -926,14 +1025,9 @@ Config::Role Config::getAdminRole (Json::Value const& params, beast::IP::Endpoin
return role;
}
//------------------------------------------------------------------------------
beast::File const& Config::getModuleDatabasePath ()
{
return m_moduleDbPath;
}
//
//
//------------------------------------------------------------------------------
} // ripple

View File

@@ -25,10 +25,13 @@
#include <beast/http/URL.h>
#include <beast/module/core/files/File.h>
#include <beast/module/core/text/StringPairArray.h>
#include <beast/utility/ci_char_traits.h>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <cstdint>
#include <map>
#include <string>
#include <type_traits>
#include <vector>
namespace ripple {
@@ -59,24 +62,97 @@ parseKeyValueSection (IniFileSections& secSource,
//------------------------------------------------------------------------------
/** Holds a collection of configuration values.
A configuration file contains zero or more sections.
*/
class Section
{
private:
std::vector <std::string> lines_;
std::map <std::string, std::string, beast::ci_less> map_;
public:
/** Create an empty section. */
Section() = default;
/** Append a set of lines to this section.
Parsable key/value pairs are also added to the map.
*/
void
append (std::vector <std::string> const& lines);
/** Returns `true` if a key with the given name exists. */
bool
exists (std::string const& name) const;
/** Retrieve a key/value pair.
@return A pair with bool `true` if the string was found.
*/
std::pair <std::string, bool>
find (std::string const& name) const;
};
//------------------------------------------------------------------------------
/** Holds unparsed configuration information.
The raw data sections are processed with intermediate parsers specific
to each module instead of being all parsed in a central location.
*/
class BasicConfig
{
public:
/** The entire, unprocessed content of the config file.
Normally clients should not need to look at this.
*/
std::string file_contents;
private:
std::map <std::string, Section, beast::ci_less> map_;
/** Preprocessed contents of each section. */
//std::map <std::string,
public:
/** Returns `true` if a section with the given name exists. */
bool
exists (std::string const& name) const;
/** Returns the section with the given name.
If the section does not exist, an empty section is returned.
*/
/** @{ */
Section const&
section (std::string const& name) const;
Section const&
operator[] (std::string const& name) const
{
return section(name);
}
/** @} */
protected:
void
build (IniFileSections const& ifs);
};
//------------------------------------------------------------------------------
/** Retrieve a key/value pair from a section.
@return The value string converted to T if it exists
and can be parsed, or else defaultValue.
*/
template <class T>
T
get (Section const& section,
std::string const& name, T const& defaultValue = T{})
{
auto const result = section.find (name);
if (! result.second)
return defaultValue;
try
{
return boost::lexical_cast <T> (result.first);
}
catch(...)
{
}
return defaultValue;
}
//------------------------------------------------------------------------------
// VFALCO TODO Replace these with beast "unsigned long long" generators
// VFALCO NOTE Apparently these are used elsewhere. Make them constants in the config
// or in the Application