feat(Core/Config): implement loading files optional (#8198)

This commit is contained in:
Kargatum
2021-12-10 17:53:31 +07:00
committed by GitHub
parent e5cbba1c4c
commit 0f1c0c154d
6 changed files with 142 additions and 101 deletions

View File

@@ -89,3 +89,6 @@ set_property(CACHE WITH_SOURCE_TREE PROPERTY STRINGS no flat hierarchical)
# If disable - use c++17 # If disable - use c++17
option(USE_CPP_20 "Enable c++20 standard" 0) option(USE_CPP_20 "Enable c++20 standard" 0)
# Config abort
option(CONFIG_ABORT_INCORRECT_OPTIONS "Enable abort if core found incorrect option in config files" 0)

View File

@@ -188,4 +188,12 @@ if (USE_CPP_20)
message(" *** Please note that this is an experimental feature!") message(" *** Please note that this is an experimental feature!")
endif() endif()
if (CONFIG_ABORT_INCORRECT_OPTIONS)
message("")
message(" WARNING !")
message(" Enabled abort if core found incorrect option in config files")
add_definitions(-DCONFIG_ABORT_INCORRECT_OPTIONS)
endif()
message("") message("")

View File

@@ -20,6 +20,7 @@
#include "StringConvert.h" #include "StringConvert.h"
#include "StringFormat.h" #include "StringFormat.h"
#include "Util.h" #include "Util.h"
#include "Tokenize.h"
#include <fstream> #include <fstream>
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
@@ -31,64 +32,82 @@ namespace
std::vector<std::string> _args; std::vector<std::string> _args;
std::unordered_map<std::string /*name*/, std::string /*value*/> _configOptions; std::unordered_map<std::string /*name*/, std::string /*value*/> _configOptions;
std::mutex _configLock; std::mutex _configLock;
bool _usingDistConfig = false;
// Check system configs like *server.conf* // Check system configs like *server.conf*
bool IsAppConfig(std::string_view fileName) bool IsAppConfig(std::string_view fileName)
{ {
size_t found = fileName.find_first_of("authserver.conf"); size_t foundAuth = fileName.find("authserver.conf");
if (found != std::string::npos) size_t foundWorld = fileName.find("worldserver.conf");
{
return true;
}
found = fileName.find_first_of("worldserver.conf"); return foundAuth != std::string_view::npos || foundWorld != std::string_view::npos;
if (found != std::string::npos) }
{
return true;
}
return false; // Check logging system configs like Appender.* and Logger.*
bool IsLoggingSystemOptions(std::string_view optionName)
{
size_t foundAppender = optionName.find("Appender.");
size_t foundLogger = optionName.find("Logger.");
return foundAppender != std::string_view::npos || foundLogger != std::string_view::npos;
} }
template<typename Format, typename... Args> template<typename Format, typename... Args>
inline void PrintError(std::string_view filename, Format&& fmt, Args&& ... args) inline void PrintError(std::string_view filename, Format&& fmt, Args&& ... args)
{ {
std::string message = Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...); std::string message = Acore::StringFormatFmt(std::forward<Format>(fmt), std::forward<Args>(args)...);
if (IsAppConfig(filename)) if (IsAppConfig(filename))
{ {
printf("%s\n", message.c_str()); fmt::print("{}\n", message);
} }
else else
{ {
LOG_ERROR("server.loading", "%s", message.c_str()); FMT_LOG_ERROR("server.loading", message);
} }
} }
void AddKey(std::string const& optionName, std::string const& optionKey, bool replace = true) void AddKey(std::string const& optionName, std::string const& optionKey, std::string_view fileName, bool isOptional, [[maybe_unused]] bool isReload)
{ {
auto const& itr = _configOptions.find(optionName); auto const& itr = _configOptions.find(optionName);
if (itr != _configOptions.end())
// Check old option
if (isOptional && itr == _configOptions.end())
{ {
if (!replace) if (!IsLoggingSystemOptions(optionName) && !isReload)
{ {
LOG_ERROR("server.loading", "> Config: Option '%s' is exist! Option key - '%s'", optionName.c_str(), itr->second.c_str()); PrintError(fileName, "> Config::LoadFile: Found incorrect option '{}' in config file '{}'. Skip", optionName, fileName);
#ifdef CONFIG_ABORT_INCORRECT_OPTIONS
ABORT_MSG("> Core can't start if found incorrect options");
#endif
return; return;
} }
}
// Check exit option
if (itr != _configOptions.end())
{
_configOptions.erase(optionName); _configOptions.erase(optionName);
} }
_configOptions.emplace(optionName, optionKey); _configOptions.emplace(optionName, optionKey);
} }
void ParseFile(std::string const& file) bool ParseFile(std::string const& file, bool isOptional, bool isReload)
{ {
std::ifstream in(file); std::ifstream in(file);
if (in.fail()) if (in.fail())
{ {
throw ConfigException(Acore::StringFormat("Config::LoadFile: Failed open file '%s'", file.c_str())); if (isOptional)
{
// No display erorr if file optional
return false;
}
throw ConfigException(Acore::StringFormatFmt("Config::LoadFile: Failed open {}file '{}'", isOptional ? "optional " : "", file));
} }
uint32 count = 0; uint32 count = 0;
@@ -100,7 +119,7 @@ namespace
auto const& itr = fileConfigs.find(confOption); auto const& itr = fileConfigs.find(confOption);
if (itr != fileConfigs.end()) if (itr != fileConfigs.end())
{ {
PrintError(file, "> Config::LoadFile: Dublicate key name '%s' in config file '%s'", std::string(confOption).c_str(), file.c_str()); PrintError(file, "> Config::LoadFile: Dublicate key name '{}' in config file '{}'", confOption, file);
return true; return true;
} }
@@ -116,7 +135,7 @@ namespace
// read line error // read line error
if (!in.good() && !in.eof()) if (!in.good() && !in.eof())
{ {
throw ConfigException(Acore::StringFormat("> Config::LoadFile: Failure to read line number %u in file '%s'", lineNumber, file.c_str())); throw ConfigException(Acore::StringFormatFmt("> Config::LoadFile: Failure to read line number {} in file '{}'", lineNumber, file));
} }
// remove whitespace in line // remove whitespace in line
@@ -143,7 +162,7 @@ namespace
if (equal_pos == std::string::npos || equal_pos == line.length()) if (equal_pos == std::string::npos || equal_pos == line.length())
{ {
PrintError(file, "> Config::LoadFile: Failure to read line number %u in file '%s'. Skip this line", lineNumber, file.c_str()); PrintError(file, "> Config::LoadFile: Failure to read line number {} in file '{}'. Skip this line", lineNumber, file);
continue; continue;
} }
@@ -166,43 +185,50 @@ namespace
// No lines read // No lines read
if (!count) if (!count)
{ {
throw ConfigException(Acore::StringFormat("Config::LoadFile: Empty file '%s'", file.c_str())); if (isOptional)
{
// No display erorr if file optional
return false;
}
throw ConfigException(Acore::StringFormatFmt("Config::LoadFile: Empty file '{}'", file));
} }
// Add correct keys if file load without errors // Add correct keys if file load without errors
for (auto const& [entry, key] : fileConfigs) for (auto const& [entry, key] : fileConfigs)
{ {
AddKey(entry, key); AddKey(entry, key, file, isOptional, isReload);
} }
return true;
} }
bool LoadFile(std::string const& file) bool LoadFile(std::string const& file, bool isOptional, bool isReload)
{ {
try try
{ {
ParseFile(file); return ParseFile(file, isOptional, isReload);
return true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
PrintError(file, "> %s", e.what()); PrintError(file, "> {}", e.what());
} }
return false; return false;
} }
} }
bool ConfigMgr::LoadInitial(std::string const& file) bool ConfigMgr::LoadInitial(std::string const& file, bool isReload /*= false*/)
{ {
std::lock_guard<std::mutex> lock(_configLock); std::lock_guard<std::mutex> lock(_configLock);
_configOptions.clear(); _configOptions.clear();
return LoadFile(file); return LoadFile(file, false, isReload);
} }
bool ConfigMgr::LoadAdditionalFile(std::string file) bool ConfigMgr::LoadAdditionalFile(std::string file, bool isOptional /*= false*/, bool isReload /*= false*/)
{ {
std::lock_guard<std::mutex> lock(_configLock); std::lock_guard<std::mutex> lock(_configLock);
return LoadFile(file); return LoadFile(file, isOptional, isReload);
} }
ConfigMgr* ConfigMgr::instance() ConfigMgr* ConfigMgr::instance()
@@ -213,12 +239,12 @@ ConfigMgr* ConfigMgr::instance()
bool ConfigMgr::Reload() bool ConfigMgr::Reload()
{ {
if (!LoadAppConfigs()) if (!LoadAppConfigs(true))
{ {
return false; return false;
} }
return LoadModulesConfigs(); return LoadModulesConfigs(true, false);
} }
template<class T> template<class T>
@@ -229,8 +255,8 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog
{ {
if (showLogs) if (showLogs)
{ {
LOG_ERROR("server.loading", "> Config: Missing name %s in config, add \"%s = %s\"", FMT_LOG_ERROR("server.loading", "> Config: Missing property {} in all config files, at least the .dist file must contain: \"{} = {}\"",
name.c_str(), name.c_str(), Acore::ToString(def).c_str()); name, name, Acore::ToString(def));
} }
return def; return def;
@@ -241,8 +267,8 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog
{ {
if (showLogs) if (showLogs)
{ {
LOG_ERROR("server.loading", "> Config: Bad value defined for name '%s', going to use '%s' instead", FMT_LOG_ERROR("server.loading", "> Config: Bad value defined for name '{}', going to use '{}' instead",
name.c_str(), Acore::ToString(def).c_str()); name, Acore::ToString(def));
} }
return def; return def;
@@ -259,8 +285,8 @@ std::string ConfigMgr::GetValueDefault<std::string>(std::string const& name, std
{ {
if (showLogs) if (showLogs)
{ {
LOG_ERROR("server.loading", "> Config: Missing name %s in config, add \"%s = %s\"", FMT_LOG_ERROR("server.loading", "> Config: Missing option {}, add \"{} = {}\"",
name.c_str(), name.c_str(), def.c_str()); name, name, def);
} }
return def; return def;
@@ -285,8 +311,8 @@ bool ConfigMgr::GetOption<bool>(std::string const& name, bool const& def, bool s
{ {
if (showLogs) if (showLogs)
{ {
LOG_ERROR("server.loading", "> Config: Bad value defined for name '%s', going to use '%s' instead", FMT_LOG_ERROR("server.loading", "> Config: Bad value defined for name '{}', going to use '{}' instead",
name.c_str(), def ? "true" : "false"); name, def ? "true" : "false");
} }
return def; return def;
@@ -302,18 +328,20 @@ std::vector<std::string> ConfigMgr::GetKeysByString(std::string const& name)
std::vector<std::string> keys; std::vector<std::string> keys;
for (auto const& [optionName, key] : _configOptions) for (auto const& [optionName, key] : _configOptions)
{
if (!optionName.compare(0, name.length(), name)) if (!optionName.compare(0, name.length(), name))
{ {
keys.emplace_back(optionName); keys.emplace_back(optionName);
} }
}
return keys; return keys;
} }
std::string const& ConfigMgr::GetFilename() std::string const ConfigMgr::GetFilename()
{ {
std::lock_guard<std::mutex> lock(_configLock); std::lock_guard<std::mutex> lock(_configLock);
return _filename; return _usingDistConfig ? _filename + ".dist" : _filename;
} }
std::vector<std::string> const& ConfigMgr::GetArguments() const std::vector<std::string> const& ConfigMgr::GetArguments() const
@@ -340,38 +368,44 @@ void ConfigMgr::Configure(std::string const& initFileName, std::vector<std::stri
// Add modules config if exist // Add modules config if exist
if (!modulesConfigList.empty()) if (!modulesConfigList.empty())
{ {
Tokenizer configFileList(modulesConfigList, ','); for (auto const& itr : Acore::Tokenize(modulesConfigList, ',', false))
for (auto const& itr : configFileList)
{ {
_additonalFiles.emplace_back(std::string(itr)); _additonalFiles.emplace_back(itr);
} }
} }
} }
bool ConfigMgr::LoadAppConfigs() bool ConfigMgr::LoadAppConfigs(bool isReload /*= false*/)
{ {
// #1 - Load init config file .conf.dist // #1 - Load init config file .conf.dist
if (!LoadInitial(_filename + ".dist")) if (!LoadInitial(_filename + ".dist", isReload))
{ {
return false; return false;
} }
// #2 - Load .conf file // #2 - Load .conf file
if (!LoadAdditionalFile(_filename)) if (!LoadAdditionalFile(_filename, true, isReload))
{ {
return false; _usingDistConfig = true;
} }
return true; return true;
} }
bool ConfigMgr::LoadModulesConfigs() bool ConfigMgr::LoadModulesConfigs(bool isReload /*= false*/, bool isNeedPrintInfo /*= true*/)
{ {
if (_additonalFiles.empty()) if (_additonalFiles.empty())
{ {
// Send successful load if no found files
return true; return true;
} }
if (isNeedPrintInfo)
{
FMT_LOG_INFO("server.loading", " ");
FMT_LOG_INFO("server.loading", "Loading modules configuration...");
}
// Start loading module configs // Start loading module configs
std::string const& moduleConfigPath = GetConfigPath() + "modules/"; std::string const& moduleConfigPath = GetConfigPath() + "modules/";
bool isExistDefaultConfig = true; bool isExistDefaultConfig = true;
@@ -387,16 +421,16 @@ bool ConfigMgr::LoadModulesConfigs()
} }
// Load .conf.dist config // Load .conf.dist config
if (!LoadAdditionalFile(moduleConfigPath + distFileName)) isExistDistConfig = LoadAdditionalFile(moduleConfigPath + distFileName, false, isReload);
if (!isReload && !isExistDistConfig)
{ {
isExistDistConfig = false; FMT_LOG_FATAL("server.loading", "> ConfigMgr::LoadModulesConfigs: Not found original config '{}'. Stop loading", distFileName);
ABORT();
} }
// Load .conf config // Load .conf config
if (!LoadAdditionalFile(moduleConfigPath + defaultFileName)) isExistDefaultConfig = LoadAdditionalFile(moduleConfigPath + defaultFileName, true, isReload);
{
isExistDefaultConfig = false;
}
if (isExistDefaultConfig && isExistDistConfig) if (isExistDefaultConfig && isExistDistConfig)
{ {
@@ -408,27 +442,32 @@ bool ConfigMgr::LoadModulesConfigs()
} }
} }
// If module configs not exist - no load if (isNeedPrintInfo)
return !_moduleConfigFiles.empty();
}
void ConfigMgr::PrintLoadedModulesConfigs()
{
// Print modules configurations
LOG_INFO("server.loading", " ");
LOG_INFO("server.loading", "Using modules configuration:");
for (auto const& itr : _moduleConfigFiles)
{ {
LOG_INFO("server.loading", "> %s", itr.c_str()); if (!_moduleConfigFiles.empty())
{
// Print modules configurations
FMT_LOG_INFO("server.loading", " ");
FMT_LOG_INFO("server.loading", "Using modules configuration:");
for (auto const& itr : _moduleConfigFiles)
{
FMT_LOG_INFO("server.loading", "> {}", itr);
}
}
else
{
FMT_LOG_INFO("server.loading", "> Not found modules config files");
}
} }
LOG_INFO("server.loading", " "); if (isNeedPrintInfo)
} {
FMT_LOG_INFO("server.loading", " ");
}
/* return true;
* Deprecated geters. This geters will be deleted }
*/
// @deprecated DO NOT USE - use GetOption<std::string> instead. // @deprecated DO NOT USE - use GetOption<std::string> instead.
std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def, bool showLogs /*= true*/) std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def, bool showLogs /*= true*/)
@@ -454,10 +493,6 @@ float ConfigMgr::GetFloatDefault(std::string const& name, float def, bool showLo
return GetOption<float>(name, def, showLogs); return GetOption<float>(name, def, showLogs);
} }
/*
* End deprecated geters
*/
#define TEMPLATE_CONFIG_OPTION(__typename) \ #define TEMPLATE_CONFIG_OPTION(__typename) \
template __typename ConfigMgr::GetOption<__typename>(std::string const& name, __typename const& def, bool showLogs /*= true*/) const; template __typename ConfigMgr::GetOption<__typename>(std::string const& name, __typename const& def, bool showLogs /*= true*/) const;

View File

@@ -20,7 +20,7 @@
#include "Define.h" #include "Define.h"
#include <stdexcept> #include <stdexcept>
#include <string> #include <string_view>
#include <vector> #include <vector>
class ConfigMgr class ConfigMgr
@@ -31,15 +31,15 @@ class ConfigMgr
~ConfigMgr() = default; ~ConfigMgr() = default;
public: public:
bool LoadAppConfigs(); bool LoadAppConfigs(bool isReload = false);
bool LoadModulesConfigs(); bool LoadModulesConfigs(bool isReload = false, bool isNeedPrintInfo = true);
void Configure(std::string const& initFileName, std::vector<std::string> args, std::string const& modulesConfigList = ""); void Configure(std::string const& initFileName, std::vector<std::string> args, std::string const& modulesConfigList = "");
static ConfigMgr* instance(); static ConfigMgr* instance();
bool Reload(); bool Reload();
std::string const& GetFilename(); std::string const GetFilename();
std::string const GetConfigPath(); std::string const GetConfigPath();
std::vector<std::string> const& GetArguments() const; std::vector<std::string> const& GetArguments() const;
std::vector<std::string> GetKeysByString(std::string const& name); std::vector<std::string> GetKeysByString(std::string const& name);
@@ -51,16 +51,16 @@ public:
* Deprecated geters. This geters will be deleted * Deprecated geters. This geters will be deleted
*/ */
// @deprecated DO NOT USE - use GetOption<std::string> instead. [[deprecated("Use GetOption<std::string> instead")]]
std::string GetStringDefault(std::string const& name, const std::string& def, bool showLogs = true); std::string GetStringDefault(std::string const& name, const std::string& def, bool showLogs = true);
// @deprecated DO NOT USE - use GetOption<bool> instead. [[deprecated("Use GetOption<bool> instead")]]
bool GetBoolDefault(std::string const& name, bool def, bool showLogs = true); bool GetBoolDefault(std::string const& name, bool def, bool showLogs = true);
// @deprecated DO NOT USE - use GetOption<int32> instead. [[deprecated("Use GetOption<int32> instead")]]
int GetIntDefault(std::string const& name, int def, bool showLogs = true); int GetIntDefault(std::string const& name, int def, bool showLogs = true);
// @deprecated DO NOT USE - use GetOption<float> instead. [[deprecated("Use GetOption<float> instead")]]
float GetFloatDefault(std::string const& name, float def, bool showLogs = true); float GetFloatDefault(std::string const& name, float def, bool showLogs = true);
/* /*
@@ -70,12 +70,10 @@ public:
bool isDryRun() { return dryRun; } bool isDryRun() { return dryRun; }
void setDryRun(bool mode) { dryRun = mode; } void setDryRun(bool mode) { dryRun = mode; }
void PrintLoadedModulesConfigs();
private: private:
/// Method used only for loading main configuration files (authserver.conf and worldserver.conf) /// Method used only for loading main configuration files (authserver.conf and worldserver.conf)
bool LoadInitial(std::string const& file); bool LoadInitial(std::string const& file, bool isReload = false);
bool LoadAdditionalFile(std::string file); bool LoadAdditionalFile(std::string file, bool isOptional = false, bool isReload = false);
template<class T> template<class T>
T GetValueDefault(std::string const& name, T const& def, bool showLogs = true) const; T GetValueDefault(std::string const& name, T const& def, bool showLogs = true) const;

View File

@@ -67,7 +67,7 @@ void Log::CreateAppenderFromConfig(std::string const& appenderName)
// Format = type, level, flags, optional1, optional2 // Format = type, level, flags, optional1, optional2
// if type = File. optional1 = file and option2 = mode // if type = File. optional1 = file and option2 = mode
// if type = Console. optional1 = Color // if type = Console. optional1 = Color
std::string options = sConfigMgr->GetStringDefault(appenderName, ""); std::string options = sConfigMgr->GetOption<std::string>(appenderName, "");
std::vector<std::string_view> tokens = Acore::Tokenize(options, ',', true); std::vector<std::string_view> tokens = Acore::Tokenize(options, ',', true);
@@ -130,7 +130,7 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
LogLevel level = LOG_LEVEL_DISABLED; LogLevel level = LOG_LEVEL_DISABLED;
std::string options = sConfigMgr->GetStringDefault(appenderName, ""); std::string options = sConfigMgr->GetOption<std::string>(appenderName, "");
std::string name = appenderName.substr(7); std::string name = appenderName.substr(7);
if (options.empty()) if (options.empty())

View File

@@ -195,14 +195,11 @@ int main(int argc, char** argv)
} }
// Add file and args in config // Add file and args in config
sConfigMgr->Configure(configFile, std::vector<std::string>(argv, argv + argc), CONFIG_FILE_LIST); sConfigMgr->Configure(configFile, { argv, argv + argc }, CONFIG_FILE_LIST);
if (!sConfigMgr->LoadAppConfigs()) if (!sConfigMgr->LoadAppConfigs())
return 1; return 1;
// Loading modules configs
sConfigMgr->LoadModulesConfigs();
std::shared_ptr<Acore::Asio::IoContext> ioContext = std::make_shared<Acore::Asio::IoContext>(); std::shared_ptr<Acore::Asio::IoContext> ioContext = std::make_shared<Acore::Asio::IoContext>();
// Init all logs // Init all logs
@@ -318,8 +315,8 @@ int main(int argc, char** argv)
Acore::Module::SetEnableModulesList(AC_MODULES_LIST); Acore::Module::SetEnableModulesList(AC_MODULES_LIST);
// Loading modules configs // Loading modules configs before scripts
sConfigMgr->PrintLoadedModulesConfigs(); sConfigMgr->LoadModulesConfigs();
///- Initialize the World ///- Initialize the World
sSecretMgr->Initialize(); sSecretMgr->Initialize();
@@ -457,7 +454,7 @@ bool StartDB()
return false; return false;
///- Get the realm Id from the configuration file ///- Get the realm Id from the configuration file
realm.Id.Realm = sConfigMgr->GetIntDefault("RealmID", 0); realm.Id.Realm = sConfigMgr->GetOption<uint32>("RealmID", 0);
if (!realm.Id.Realm) if (!realm.Id.Realm)
{ {
LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file"); LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");