mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-25 06:36:24 +00:00
Merge branch 'master' into Playerbot
This commit is contained in:
@@ -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())
|
||||
{
|
||||
if (showLogs)
|
||||
Optional<std::string> envVar = EnvVarForIniKey(name);
|
||||
if (!envVar)
|
||||
{
|
||||
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
|
||||
name, _filename, name, Acore::ToString(def));
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
|
||||
name, _filename, name, Acore::ToString(def));
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
return def;
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
|
||||
name.c_str(), _filename.c_str(), envVar->c_str());
|
||||
}
|
||||
|
||||
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.",
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
|
||||
bool Reload();
|
||||
|
||||
/// Overrides configuration with environment variables and returns overridden keys
|
||||
std::vector<std::string> OverrideWithEnvVariablesIfAny();
|
||||
|
||||
std::string const GetFilename();
|
||||
std::string const GetConfigPath();
|
||||
[[nodiscard]] std::vector<std::string> const& GetArguments() const;
|
||||
|
||||
Reference in New Issue
Block a user