summaryrefslogtreecommitdiff
path: root/src/common/Configuration/Config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/Configuration/Config.cpp')
-rw-r--r--src/common/Configuration/Config.cpp145
1 files changed, 140 insertions, 5 deletions
diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp
index d5750120d0..d01d3f7b88 100644
--- a/src/common/Configuration/Config.cpp
+++ b/src/common/Configuration/Config.cpp
@@ -21,6 +21,7 @@
#include "StringFormat.h"
#include "Tokenize.h"
#include "Util.h"
+#include <cstdlib>
#include <fstream>
#include <mutex>
#include <unordered_map>
@@ -215,6 +216,81 @@ namespace
return false;
}
+
+ // Converts ini keys to the environment variable key (upper snake case).
+ // Example of conversions:
+ // SomeConfig => SOME_CONFIG
+ // myNestedConfig.opt1 => MY_NESTED_CONFIG_OPT_1
+ // LogDB.Opt.ClearTime => LOG_DB_OPT_CLEAR_TIME
+ std::string IniKeyToEnvVarKey(std::string const& key)
+ {
+ std::string result;
+
+ const char* str = key.c_str();
+ size_t n = key.length();
+
+ char curr;
+ bool isEnd;
+ bool nextIsUpper;
+ bool currIsNumeric;
+ bool nextIsNumeric;
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ curr = str[i];
+ if (curr == ' ' || curr == '.' || curr == '-')
+ {
+ result += '_';
+ continue;
+ }
+
+ isEnd = i == n - 1;
+ if (!isEnd)
+ {
+ nextIsUpper = isupper(str[i + 1]);
+
+ // handle "aB" to "A_B"
+ if (!isupper(curr) && nextIsUpper)
+ {
+ result += static_cast<char>(std::toupper(curr));
+ result += '_';
+ continue;
+ }
+
+ currIsNumeric = isNumeric(curr);
+ nextIsNumeric = isNumeric(str[i + 1]);
+
+ // handle "a1" to "a_1"
+ if (!currIsNumeric && nextIsNumeric)
+ {
+ result += static_cast<char>(std::toupper(curr));
+ result += '_';
+ continue;
+ }
+
+ // handle "1a" to "1_a"
+ if (currIsNumeric && !nextIsNumeric)
+ {
+ result += static_cast<char>(std::toupper(curr));
+ result += '_';
+ continue;
+ }
+ }
+
+ result += static_cast<char>(std::toupper(curr));
+ }
+ return result;
+ }
+
+ Optional<std::string> EnvVarForIniKey(std::string const& key)
+ {
+ std::string envKey = "AC_" + IniKeyToEnvVarKey(key);
+ char* val = std::getenv(envKey.c_str());
+ if (!val)
+ return std::nullopt;
+
+ return std::string(val);
+ }
}
bool ConfigMgr::LoadInitial(std::string const& file, bool isReload /*= false*/)
@@ -243,25 +319,72 @@ bool ConfigMgr::Reload()
return false;
}
- return LoadModulesConfigs(true, false);
+ if (!LoadModulesConfigs(true, false))
+ {
+ return false;
+ }
+
+ OverrideWithEnvVariablesIfAny();
+
+ return true;
+}
+
+std::vector<std::string> ConfigMgr::OverrideWithEnvVariablesIfAny()
+{
+ std::lock_guard<std::mutex> lock(_configLock);
+
+ std::vector<std::string> overriddenKeys;
+
+ for (auto& itr : _configOptions)
+ {
+ if (itr.first.empty())
+ continue;
+
+ Optional<std::string> envVar = EnvVarForIniKey(itr.first);
+ if (!envVar)
+ continue;
+
+ itr.second = *envVar;
+
+ overriddenKeys.push_back(itr.first);
+ }
+
+ return overriddenKeys;
}
template<class T>
T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLogs /*= true*/) const
{
+ std::string strValue;
auto const& itr = _configOptions.find(name);
if (itr == _configOptions.end())
{
+ Optional<std::string> envVar = EnvVarForIniKey(name);
+ if (!envVar)
+ {
+ if (showLogs)
+ {
+ LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
+ name, _filename, name, Acore::ToString(def));
+ }
+
+ return def;
+ }
+
if (showLogs)
{
- LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
- name, _filename, name, Acore::ToString(def));
+ LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
+ name.c_str(), _filename.c_str(), envVar->c_str());
}
- return def;
+ strValue = *envVar;
+ }
+ else
+ {
+ strValue = itr->second;
}
- auto value = Acore::StringTo<T>(itr->second);
+ auto value = Acore::StringTo<T>(strValue);
if (!value)
{
if (showLogs)
@@ -282,6 +405,18 @@ std::string ConfigMgr::GetValueDefault<std::string>(std::string const& name, std
auto const& itr = _configOptions.find(name);
if (itr == _configOptions.end())
{
+ Optional<std::string> envVar = EnvVarForIniKey(name);
+ if (envVar)
+ {
+ if (showLogs)
+ {
+ LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
+ name.c_str(), _filename.c_str(), envVar->c_str());
+ }
+
+ return *envVar;
+ }
+
if (showLogs)
{
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",