|
|
|
@ -22,42 +22,45 @@ namespace llarp
|
|
|
|
|
{
|
|
|
|
|
namespace config
|
|
|
|
|
{
|
|
|
|
|
// Base class for the following option flag types
|
|
|
|
|
struct option_flag
|
|
|
|
|
{};
|
|
|
|
|
|
|
|
|
|
struct Required_t : option_flag
|
|
|
|
|
{};
|
|
|
|
|
struct Hidden_t : option_flag
|
|
|
|
|
{};
|
|
|
|
|
struct MultiValue_t : option_flag
|
|
|
|
|
{};
|
|
|
|
|
struct RelayOnly_t : option_flag
|
|
|
|
|
{};
|
|
|
|
|
struct ClientOnly_t : option_flag
|
|
|
|
|
{};
|
|
|
|
|
struct Deprecated_t : option_flag
|
|
|
|
|
{};
|
|
|
|
|
namespace flag
|
|
|
|
|
{
|
|
|
|
|
// Base class for the following option flag types
|
|
|
|
|
struct opt
|
|
|
|
|
{};
|
|
|
|
|
|
|
|
|
|
struct REQUIRED : opt
|
|
|
|
|
{};
|
|
|
|
|
struct HIDDEN : opt
|
|
|
|
|
{};
|
|
|
|
|
struct MULTIVALUE : opt
|
|
|
|
|
{};
|
|
|
|
|
struct RELAYONLY : opt
|
|
|
|
|
{};
|
|
|
|
|
struct CLIENTONLY : opt
|
|
|
|
|
{};
|
|
|
|
|
struct DEPRECATED : opt
|
|
|
|
|
{};
|
|
|
|
|
} // namespace flag
|
|
|
|
|
|
|
|
|
|
/// Value to pass for an OptionDefinition to indicate that the option is required
|
|
|
|
|
inline constexpr Required_t Required{};
|
|
|
|
|
inline constexpr flag::REQUIRED Required{};
|
|
|
|
|
/// Value to pass for an OptionDefinition to indicate that the option should be hidden from the
|
|
|
|
|
/// generate config file if it is unset (and has no comment). Typically for deprecated, renamed
|
|
|
|
|
/// options that still do something, and for internal dev options that aren't usefully exposed.
|
|
|
|
|
/// (For do-nothing deprecated options use Deprecated instead).
|
|
|
|
|
inline constexpr Hidden_t Hidden{};
|
|
|
|
|
inline constexpr flag::HIDDEN Hidden{};
|
|
|
|
|
/// Value to pass for an OptionDefinition to indicate that the option takes multiple values
|
|
|
|
|
inline constexpr MultiValue_t MultiValue{};
|
|
|
|
|
inline constexpr flag::MULTIVALUE MultiValue{};
|
|
|
|
|
/// Value to pass for an option that should only be set for relay configs. If found in a client
|
|
|
|
|
/// config it be ignored (but will produce a warning).
|
|
|
|
|
inline constexpr RelayOnly_t RelayOnly{};
|
|
|
|
|
inline constexpr flag::RELAYONLY RelayOnly{};
|
|
|
|
|
/// Value to pass for an option that should only be set for client configs. If found in a relay
|
|
|
|
|
/// config it will be ignored (but will produce a warning).
|
|
|
|
|
inline constexpr ClientOnly_t ClientOnly{};
|
|
|
|
|
inline constexpr flag::CLIENTONLY ClientOnly{};
|
|
|
|
|
/// Value to pass for an option that is deprecated and does nothing and should be ignored (with
|
|
|
|
|
/// a deprecation warning) if specified. Note that Deprecated implies Hidden, and that
|
|
|
|
|
/// {client,relay}-only options in a {relay,client} config are also considered Deprecated.
|
|
|
|
|
inline constexpr Deprecated_t Deprecated{};
|
|
|
|
|
inline constexpr flag::DEPRECATED Deprecated{};
|
|
|
|
|
|
|
|
|
|
/// Wrapper to specify a default value to an OptionDefinition
|
|
|
|
|
template <typename T>
|
|
|
|
@ -82,7 +85,7 @@ namespace llarp
|
|
|
|
|
/// particular, a reference to a local variable may be problematic.
|
|
|
|
|
template <typename T>
|
|
|
|
|
auto
|
|
|
|
|
AssignmentAcceptor(T& ref)
|
|
|
|
|
assignment_acceptor(T& ref)
|
|
|
|
|
{
|
|
|
|
|
return [&ref](T arg) { ref = std::move(arg); };
|
|
|
|
|
}
|
|
|
|
@ -106,7 +109,7 @@ namespace llarp
|
|
|
|
|
constexpr bool is_default_array<U&> = is_default_array<remove_cvref_t<U>>;
|
|
|
|
|
|
|
|
|
|
template <typename T, typename Option>
|
|
|
|
|
constexpr bool is_option = std::is_base_of_v<option_flag, remove_cvref_t<Option>>
|
|
|
|
|
constexpr bool is_option = std::is_base_of_v<flag::opt, remove_cvref_t<Option>>
|
|
|
|
|
or std::is_same_v<Comment, Option> or is_default<Option> or is_default_array<Option>
|
|
|
|
|
or std::is_invocable_v<remove_cvref_t<Option>, T>;
|
|
|
|
|
} // namespace config
|
|
|
|
@ -121,12 +124,12 @@ namespace llarp
|
|
|
|
|
OptionDefinitionBase(std::string section_, std::string name_, const T&...)
|
|
|
|
|
: section(std::move(section_))
|
|
|
|
|
, name(std::move(name_))
|
|
|
|
|
, required{(std::is_same_v<T, config::Required_t> || ...)}
|
|
|
|
|
, multiValued{(std::is_same_v<T, config::MultiValue_t> || ...)}
|
|
|
|
|
, deprecated{(std::is_same_v<T, config::Deprecated_t> || ...)}
|
|
|
|
|
, hidden{deprecated || (std::is_same_v<T, config::Hidden_t> || ...)}
|
|
|
|
|
, relayOnly{(std::is_same_v<T, config::RelayOnly_t> || ...)}
|
|
|
|
|
, clientOnly{(std::is_same_v<T, config::ClientOnly_t> || ...)}
|
|
|
|
|
, required{(std::is_same_v<T, config::flag::REQUIRED> || ...)}
|
|
|
|
|
, multi_valued{(std::is_same_v<T, config::flag::MULTIVALUE> || ...)}
|
|
|
|
|
, deprecated{(std::is_same_v<T, config::flag::DEPRECATED> || ...)}
|
|
|
|
|
, hidden{deprecated || (std::is_same_v<T, config::flag::HIDDEN> || ...)}
|
|
|
|
|
, relay_only{(std::is_same_v<T, config::flag::RELAYONLY> || ...)}
|
|
|
|
|
, clientOnly{(std::is_same_v<T, config::flag::CLIENTONLY> || ...)}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
virtual ~OptionDefinitionBase() = default;
|
|
|
|
@ -135,39 +138,39 @@ namespace llarp
|
|
|
|
|
///
|
|
|
|
|
/// @return the option's default value represented as a string
|
|
|
|
|
virtual std::vector<std::string>
|
|
|
|
|
defaultValuesAsString() = 0;
|
|
|
|
|
default_values_as_string() = 0;
|
|
|
|
|
|
|
|
|
|
/// Subclasses should parse and store the provided input
|
|
|
|
|
///
|
|
|
|
|
/// @param input is the string input to interpret
|
|
|
|
|
virtual void
|
|
|
|
|
parseValue(const std::string& input) = 0;
|
|
|
|
|
parse_value(const std::string& input) = 0;
|
|
|
|
|
|
|
|
|
|
/// Subclasses should provide the number of values found.
|
|
|
|
|
///
|
|
|
|
|
/// @return number of values found
|
|
|
|
|
virtual size_t
|
|
|
|
|
getNumberFound() const = 0;
|
|
|
|
|
get_number_found() const = 0;
|
|
|
|
|
|
|
|
|
|
/// Subclasess should write their parsed values as strings.
|
|
|
|
|
///
|
|
|
|
|
/// @return the option's value(s) as strings
|
|
|
|
|
virtual std::vector<std::string>
|
|
|
|
|
valuesAsString() = 0;
|
|
|
|
|
values_as_string() = 0;
|
|
|
|
|
|
|
|
|
|
/// Subclassess should call their acceptor, if present. See OptionDefinition for more details.
|
|
|
|
|
///
|
|
|
|
|
/// @throws if the acceptor throws or the option is required but missing
|
|
|
|
|
virtual void
|
|
|
|
|
tryAccept() const = 0;
|
|
|
|
|
try_accept() const = 0;
|
|
|
|
|
|
|
|
|
|
std::string section;
|
|
|
|
|
std::string name;
|
|
|
|
|
bool required = false;
|
|
|
|
|
bool multiValued = false;
|
|
|
|
|
bool multi_valued = false;
|
|
|
|
|
bool deprecated = false;
|
|
|
|
|
bool hidden = false;
|
|
|
|
|
bool relayOnly = false;
|
|
|
|
|
bool relay_only = false;
|
|
|
|
|
bool clientOnly = false;
|
|
|
|
|
// Temporarily holds comments given during construction until the option is actually added to
|
|
|
|
|
// the owning ConfigDefinition.
|
|
|
|
@ -188,7 +191,7 @@ namespace llarp
|
|
|
|
|
///
|
|
|
|
|
/// @param defaultValue_ is used in the following situations:
|
|
|
|
|
/// 1) as the return value for getValue() if there is no parsed value and required==false
|
|
|
|
|
/// 2) as the output in defaultValuesAsString(), used to generate config files
|
|
|
|
|
/// 2) as the output in default_values_as_string(), used to generate config files
|
|
|
|
|
/// 3) as the output in valueAsString(), used to generate config files
|
|
|
|
|
///
|
|
|
|
|
/// @param opts - 0 or more of config::Required, config::Hidden, config::Default{...}, etc.
|
|
|
|
@ -204,40 +207,40 @@ namespace llarp
|
|
|
|
|
constexpr bool has_default =
|
|
|
|
|
((config::is_default_array<Options> || config::is_default<Options>) || ...);
|
|
|
|
|
constexpr bool has_required =
|
|
|
|
|
(std::is_same_v<config::remove_cvref_t<Options>, config::Required_t> || ...);
|
|
|
|
|
(std::is_same_v<config::remove_cvref_t<Options>, config::flag::REQUIRED> || ...);
|
|
|
|
|
constexpr bool has_hidden =
|
|
|
|
|
(std::is_same_v<config::remove_cvref_t<Options>, config::Hidden_t> || ...);
|
|
|
|
|
(std::is_same_v<config::remove_cvref_t<Options>, config::flag::HIDDEN> || ...);
|
|
|
|
|
static_assert(
|
|
|
|
|
not(has_default and has_required), "Default{...} and Required are mutually exclusive");
|
|
|
|
|
static_assert(not(has_hidden and has_required), "Hidden and Required are mutually exclusive");
|
|
|
|
|
|
|
|
|
|
(extractDefault(std::forward<Options>(opts)), ...);
|
|
|
|
|
(extractAcceptor(std::forward<Options>(opts)), ...);
|
|
|
|
|
(extractComments(std::forward<Options>(opts)), ...);
|
|
|
|
|
(extract_default(std::forward<Options>(opts)), ...);
|
|
|
|
|
(extract_acceptor(std::forward<Options>(opts)), ...);
|
|
|
|
|
(extract_comments(std::forward<Options>(opts)), ...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Extracts a default value from an config::Default<U> or an array of defaults (for
|
|
|
|
|
/// multi-valued options with multi-value default); ignores anything else.
|
|
|
|
|
template <typename U>
|
|
|
|
|
void
|
|
|
|
|
extractDefault(U&& defaultValue_)
|
|
|
|
|
extract_default(U&& defaultValue_)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (config::is_default_array<U>)
|
|
|
|
|
{
|
|
|
|
|
if (!multiValued)
|
|
|
|
|
if (!multi_valued)
|
|
|
|
|
throw std::logic_error{"Array config defaults require multiValue mode"};
|
|
|
|
|
|
|
|
|
|
defaultValues.clear();
|
|
|
|
|
defaultValues.reserve(defaultValue_.size());
|
|
|
|
|
default_values.clear();
|
|
|
|
|
default_values.reserve(defaultValue_.size());
|
|
|
|
|
for (const auto& def : defaultValue_)
|
|
|
|
|
defaultValues.push_back(def.val);
|
|
|
|
|
default_values.push_back(def.val);
|
|
|
|
|
}
|
|
|
|
|
else if constexpr (config::is_default<U>)
|
|
|
|
|
{
|
|
|
|
|
static_assert(
|
|
|
|
|
std::is_convertible_v<decltype(std::forward<U>(defaultValue_).val), T>,
|
|
|
|
|
"Cannot convert given llarp::config::Default to the required value type");
|
|
|
|
|
defaultValues = {std::forward<U>(defaultValue_).val};
|
|
|
|
|
default_values = {std::forward<U>(defaultValue_).val};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -245,7 +248,7 @@ namespace llarp
|
|
|
|
|
/// that isn't callable.
|
|
|
|
|
template <typename U>
|
|
|
|
|
void
|
|
|
|
|
extractAcceptor(U&& acceptor_)
|
|
|
|
|
extract_acceptor(U&& acceptor_)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_invocable_v<U, T>)
|
|
|
|
|
acceptor = std::forward<U>(acceptor_);
|
|
|
|
@ -254,7 +257,7 @@ namespace llarp
|
|
|
|
|
/// Extracts option Comments and forwards them addOptionComments.
|
|
|
|
|
template <typename U>
|
|
|
|
|
void
|
|
|
|
|
extractComments(U&& comment)
|
|
|
|
|
extract_comments(U&& comment)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_same_v<config::remove_cvref_t<U>, config::Comment>)
|
|
|
|
|
comments = std::forward<U>(comment).comments;
|
|
|
|
@ -265,38 +268,38 @@ namespace llarp
|
|
|
|
|
///
|
|
|
|
|
/// @return an optional with the parsed value, the (first) default value, or no value.
|
|
|
|
|
std::optional<T>
|
|
|
|
|
getValue() const
|
|
|
|
|
get_value() const
|
|
|
|
|
{
|
|
|
|
|
if (parsedValues.empty())
|
|
|
|
|
if (parsed_values.empty())
|
|
|
|
|
{
|
|
|
|
|
if (required || defaultValues.empty())
|
|
|
|
|
if (required || default_values.empty())
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return defaultValues.front();
|
|
|
|
|
return default_values.front();
|
|
|
|
|
}
|
|
|
|
|
return parsedValues.front();
|
|
|
|
|
return parsed_values.front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the number of values found.
|
|
|
|
|
///
|
|
|
|
|
/// @return number of values found
|
|
|
|
|
size_t
|
|
|
|
|
getNumberFound() const override
|
|
|
|
|
get_number_found() const override
|
|
|
|
|
{
|
|
|
|
|
return parsedValues.size();
|
|
|
|
|
return parsed_values.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string>
|
|
|
|
|
defaultValuesAsString() override
|
|
|
|
|
default_values_as_string() override
|
|
|
|
|
{
|
|
|
|
|
if (defaultValues.empty())
|
|
|
|
|
if (default_values.empty())
|
|
|
|
|
return {};
|
|
|
|
|
if constexpr (std::is_same_v<fs::path, T>)
|
|
|
|
|
return {{defaultValues.front().u8string()}};
|
|
|
|
|
return {{default_values.front().u8string()}};
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> def_strs;
|
|
|
|
|
def_strs.reserve(defaultValues.size());
|
|
|
|
|
for (const auto& v : defaultValues)
|
|
|
|
|
def_strs.reserve(default_values.size());
|
|
|
|
|
for (const auto& v : default_values)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_same_v<bool, T>)
|
|
|
|
|
def_strs.push_back(fmt::format("{}", (bool)v));
|
|
|
|
@ -308,18 +311,18 @@ namespace llarp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
parseValue(const std::string& input) override
|
|
|
|
|
parse_value(const std::string& input) override
|
|
|
|
|
{
|
|
|
|
|
if (not multiValued and parsedValues.size() > 0)
|
|
|
|
|
if (not multi_valued and parsed_values.size() > 0)
|
|
|
|
|
{
|
|
|
|
|
throw std::invalid_argument{fmt::format("duplicate value for {}", name)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parsedValues.emplace_back(fromString(input));
|
|
|
|
|
parsed_values.emplace_back(from_string(input));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T
|
|
|
|
|
fromString(const std::string& input)
|
|
|
|
|
from_string(const std::string& input)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_same_v<T, std::string>)
|
|
|
|
|
{
|
|
|
|
@ -337,13 +340,13 @@ namespace llarp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string>
|
|
|
|
|
valuesAsString() override
|
|
|
|
|
values_as_string() override
|
|
|
|
|
{
|
|
|
|
|
if (parsedValues.empty())
|
|
|
|
|
if (parsed_values.empty())
|
|
|
|
|
return {};
|
|
|
|
|
std::vector<std::string> result;
|
|
|
|
|
result.reserve(parsedValues.size());
|
|
|
|
|
for (const auto& v : parsedValues)
|
|
|
|
|
result.reserve(parsed_values.size());
|
|
|
|
|
for (const auto& v : parsed_values)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_same_v<bool, T>)
|
|
|
|
|
result.push_back(fmt::format("{}", (bool)v));
|
|
|
|
@ -354,46 +357,46 @@ namespace llarp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Attempts to call the acceptor function, if present. This function may throw if the value
|
|
|
|
|
/// is not acceptable. Additionally, tryAccept should not be called if the option is required
|
|
|
|
|
/// is not acceptable. Additionally, try_accept should not be called if the option is required
|
|
|
|
|
/// and no value has been provided.
|
|
|
|
|
///
|
|
|
|
|
/// @throws if required and no value present or if the acceptor throws
|
|
|
|
|
void
|
|
|
|
|
tryAccept() const override
|
|
|
|
|
try_accept() const override
|
|
|
|
|
{
|
|
|
|
|
if (required and parsedValues.empty())
|
|
|
|
|
if (required and parsed_values.empty())
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error{fmt::format(
|
|
|
|
|
"cannot call tryAccept() on [{}]:{} when required but no value available",
|
|
|
|
|
"cannot call try_accept() on [{}]:{} when required but no value available",
|
|
|
|
|
section,
|
|
|
|
|
name)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (acceptor)
|
|
|
|
|
{
|
|
|
|
|
if (multiValued)
|
|
|
|
|
if (multi_valued)
|
|
|
|
|
{
|
|
|
|
|
// add default value in multi value mode
|
|
|
|
|
if (parsedValues.empty() and not defaultValues.empty())
|
|
|
|
|
for (const auto& v : defaultValues)
|
|
|
|
|
if (parsed_values.empty() and not default_values.empty())
|
|
|
|
|
for (const auto& v : default_values)
|
|
|
|
|
acceptor(v);
|
|
|
|
|
|
|
|
|
|
for (auto value : parsedValues)
|
|
|
|
|
for (auto value : parsed_values)
|
|
|
|
|
{
|
|
|
|
|
acceptor(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto maybe = getValue();
|
|
|
|
|
auto maybe = get_value();
|
|
|
|
|
if (maybe)
|
|
|
|
|
acceptor(*maybe);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<T> defaultValues;
|
|
|
|
|
std::vector<T> parsedValues;
|
|
|
|
|
std::vector<T> default_values;
|
|
|
|
|
std::vector<T> parsed_values;
|
|
|
|
|
std::function<void(T)> acceptor;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -401,15 +404,13 @@ namespace llarp
|
|
|
|
|
/// case because we want to accept "truthy" and "falsy" string values (e.g. "off" == false)
|
|
|
|
|
template <>
|
|
|
|
|
bool
|
|
|
|
|
OptionDefinition<bool>::fromString(const std::string& input);
|
|
|
|
|
OptionDefinition<bool>::from_string(const std::string& input);
|
|
|
|
|
|
|
|
|
|
using UndeclaredValueHandler =
|
|
|
|
|
std::function<void(std::string_view section, std::string_view name, std::string_view value)>;
|
|
|
|
|
|
|
|
|
|
using OptionDefinition_ptr = std::unique_ptr<OptionDefinitionBase>;
|
|
|
|
|
|
|
|
|
|
// map of k:v pairs
|
|
|
|
|
using DefinitionMap = std::unordered_map<std::string, OptionDefinition_ptr>;
|
|
|
|
|
using DefinitionMap = std::unordered_map<std::string, std::unique_ptr<OptionDefinitionBase>>;
|
|
|
|
|
|
|
|
|
|
// map of section-name to map-of-definitions
|
|
|
|
|
using SectionMap = std::unordered_map<std::string, DefinitionMap>;
|
|
|
|
@ -443,15 +444,15 @@ namespace llarp
|
|
|
|
|
/// @return `*this` for chaining calls
|
|
|
|
|
/// @throws std::invalid_argument if the option already exists
|
|
|
|
|
ConfigDefinition&
|
|
|
|
|
defineOption(OptionDefinition_ptr def);
|
|
|
|
|
define_option(std::unique_ptr<OptionDefinitionBase> def);
|
|
|
|
|
|
|
|
|
|
/// Convenience function which calls defineOption with a OptionDefinition of the specified
|
|
|
|
|
/// type and with parameters passed through to OptionDefinition's constructor.
|
|
|
|
|
template <typename T, typename... Params>
|
|
|
|
|
ConfigDefinition&
|
|
|
|
|
defineOption(Params&&... args)
|
|
|
|
|
define_option(Params&&... args)
|
|
|
|
|
{
|
|
|
|
|
return defineOption(std::make_unique<OptionDefinition<T>>(std::forward<Params>(args)...));
|
|
|
|
|
return define_option(std::make_unique<OptionDefinition<T>>(std::forward<Params>(args)...));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Specify a config value for the given section and name. The value should be a valid string
|
|
|
|
@ -459,7 +460,7 @@ namespace llarp
|
|
|
|
|
/// called).
|
|
|
|
|
///
|
|
|
|
|
/// If the specified option doesn't exist, an exception will be thrown. Otherwise, the
|
|
|
|
|
/// option's parseValue() will be invoked, and should throw an exception if the string can't
|
|
|
|
|
/// option's parse_value() will be invoked, and should throw an exception if the string can't
|
|
|
|
|
/// be parsed.
|
|
|
|
|
///
|
|
|
|
|
/// @param section is the section this value resides in
|
|
|
|
@ -467,7 +468,7 @@ namespace llarp
|
|
|
|
|
/// @return `*this` for chaining calls
|
|
|
|
|
/// @throws if the option doesn't exist or the provided string isn't parseable
|
|
|
|
|
ConfigDefinition&
|
|
|
|
|
addConfigValue(std::string_view section, std::string_view name, std::string_view value);
|
|
|
|
|
add_config_value(std::string_view section, std::string_view name, std::string_view value);
|
|
|
|
|
|
|
|
|
|
/// Get a config value. If the value hasn't been provided but a default has, the default will
|
|
|
|
|
/// be returned. If no value and no default is provided, an empty optional will be returned.
|
|
|
|
@ -482,9 +483,9 @@ namespace llarp
|
|
|
|
|
// provided
|
|
|
|
|
template <typename T>
|
|
|
|
|
std::optional<T>
|
|
|
|
|
getConfigValue(std::string_view section, std::string_view name)
|
|
|
|
|
get_config_value(std::string_view section, std::string_view name)
|
|
|
|
|
{
|
|
|
|
|
OptionDefinition_ptr& definition = lookupDefinitionOrThrow(section, name);
|
|
|
|
|
std::unique_ptr<OptionDefinitionBase>& definition = lookup_definition_or_throw(section, name);
|
|
|
|
|
|
|
|
|
|
auto derived = dynamic_cast<const OptionDefinition<T>*>(definition.get());
|
|
|
|
|
if (not derived)
|
|
|
|
@ -505,19 +506,19 @@ namespace llarp
|
|
|
|
|
/// @param handler
|
|
|
|
|
/// @throws if there is already a handler for this section
|
|
|
|
|
void
|
|
|
|
|
addUndeclaredHandler(const std::string& section, UndeclaredValueHandler handler);
|
|
|
|
|
add_undeclared_handler(const std::string& section, UndeclaredValueHandler handler);
|
|
|
|
|
|
|
|
|
|
/// Removes an "undeclared" handler for the given section.
|
|
|
|
|
///
|
|
|
|
|
/// @param section is the section which we want to remove the handler for
|
|
|
|
|
void
|
|
|
|
|
removeUndeclaredHandler(const std::string& section);
|
|
|
|
|
remove_undeclared_handler(const std::string& section);
|
|
|
|
|
|
|
|
|
|
/// Validate that all required fields are present.
|
|
|
|
|
///
|
|
|
|
|
/// @throws std::invalid_argument if configuration constraints are not met
|
|
|
|
|
void
|
|
|
|
|
validateRequiredFields();
|
|
|
|
|
validate_required_fields();
|
|
|
|
|
|
|
|
|
|
/// Accept all options. This will call the acceptor (if present) on each option. Note that
|
|
|
|
|
/// this should only be called if all required fields are present (that is,
|
|
|
|
@ -525,14 +526,14 @@ namespace llarp
|
|
|
|
|
///
|
|
|
|
|
/// @throws if any option's acceptor throws
|
|
|
|
|
void
|
|
|
|
|
acceptAllOptions();
|
|
|
|
|
accept_all_options();
|
|
|
|
|
|
|
|
|
|
/// validates and accept all parsed options
|
|
|
|
|
inline void
|
|
|
|
|
process()
|
|
|
|
|
{
|
|
|
|
|
validateRequiredFields();
|
|
|
|
|
acceptAllOptions();
|
|
|
|
|
validate_required_fields();
|
|
|
|
|
accept_all_options();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Add comments for a given section. Comments are replayed in-order during config file
|
|
|
|
@ -542,7 +543,7 @@ namespace llarp
|
|
|
|
|
/// @param section
|
|
|
|
|
/// @param comment
|
|
|
|
|
void
|
|
|
|
|
addSectionComments(const std::string& section, std::vector<std::string> comments);
|
|
|
|
|
add_section_comments(const std::string& section, std::vector<std::string> comments);
|
|
|
|
|
|
|
|
|
|
/// Add comments for a given option. Similar to addSectionComment, but applies to a specific
|
|
|
|
|
/// [section]:name pair.
|
|
|
|
@ -551,7 +552,7 @@ namespace llarp
|
|
|
|
|
/// @param name
|
|
|
|
|
/// @param comment
|
|
|
|
|
void
|
|
|
|
|
addOptionComments(
|
|
|
|
|
add_option_comments(
|
|
|
|
|
const std::string& section, const std::string& name, std::vector<std::string> comments);
|
|
|
|
|
|
|
|
|
|
/// Generate a config string from the current config definition, optionally using overridden
|
|
|
|
@ -566,38 +567,39 @@ namespace llarp
|
|
|
|
|
/// addConfigValue()) or only definitions
|
|
|
|
|
/// @return a string containing the config in INI format
|
|
|
|
|
std::string
|
|
|
|
|
generateINIConfig(bool useValues = false);
|
|
|
|
|
generate_ini_config(bool useValues = false);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// If true skip client-only options; if false skip relay-only options.
|
|
|
|
|
bool relay;
|
|
|
|
|
|
|
|
|
|
OptionDefinition_ptr&
|
|
|
|
|
lookupDefinitionOrThrow(std::string_view section, std::string_view name);
|
|
|
|
|
const OptionDefinition_ptr&
|
|
|
|
|
lookupDefinitionOrThrow(std::string_view section, std::string_view name) const;
|
|
|
|
|
std::unique_ptr<OptionDefinitionBase>&
|
|
|
|
|
lookup_definition_or_throw(std::string_view section, std::string_view name);
|
|
|
|
|
const std::unique_ptr<OptionDefinitionBase>&
|
|
|
|
|
lookup_definition_or_throw(std::string_view section, std::string_view name) const;
|
|
|
|
|
|
|
|
|
|
using SectionVisitor = std::function<void(const std::string&, const DefinitionMap&)>;
|
|
|
|
|
void
|
|
|
|
|
visitSections(SectionVisitor visitor) const;
|
|
|
|
|
visit_sections(SectionVisitor visitor) const;
|
|
|
|
|
|
|
|
|
|
using DefVisitor = std::function<void(const std::string&, const OptionDefinition_ptr&)>;
|
|
|
|
|
using DefVisitor =
|
|
|
|
|
std::function<void(const std::string&, const std::unique_ptr<OptionDefinitionBase>&)>;
|
|
|
|
|
void
|
|
|
|
|
visitDefinitions(const std::string& section, DefVisitor visitor) const;
|
|
|
|
|
visit_definitions(const std::string& section, DefVisitor visitor) const;
|
|
|
|
|
|
|
|
|
|
SectionMap m_definitions;
|
|
|
|
|
SectionMap definitions;
|
|
|
|
|
|
|
|
|
|
std::unordered_map<std::string, UndeclaredValueHandler> m_undeclaredHandlers;
|
|
|
|
|
std::unordered_map<std::string, UndeclaredValueHandler> undeclared_handlers;
|
|
|
|
|
|
|
|
|
|
// track insertion order. the vector<string>s are ordered list of section/option names.
|
|
|
|
|
std::vector<std::string> m_sectionOrdering;
|
|
|
|
|
std::unordered_map<std::string, std::vector<std::string>> m_definitionOrdering;
|
|
|
|
|
std::vector<std::string> section_ordering;
|
|
|
|
|
std::unordered_map<std::string, std::vector<std::string>> definition_ordering;
|
|
|
|
|
|
|
|
|
|
// comments for config file generation
|
|
|
|
|
using CommentList = std::vector<std::string>;
|
|
|
|
|
using CommentsMap = std::unordered_map<std::string, CommentList>;
|
|
|
|
|
CommentsMap m_sectionComments;
|
|
|
|
|
std::unordered_map<std::string, CommentsMap> m_definitionComments;
|
|
|
|
|
CommentsMap section_comments;
|
|
|
|
|
std::unordered_map<std::string, CommentsMap> definition_comments;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace llarp
|
|
|
|
|