diff options
Diffstat (limited to 'src/common/Configuration/Config.cpp')
| -rw-r--r-- | src/common/Configuration/Config.cpp | 145 |
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.", |
