Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-08-24 22:07:53 +08:00
96 changed files with 3271 additions and 2541 deletions

View File

@@ -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.",

View 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;