diff --git a/conf/dist/config.cmake b/conf/dist/config.cmake index 5b8779b06..329f2656e 100644 --- a/conf/dist/config.cmake +++ b/conf/dist/config.cmake @@ -89,3 +89,6 @@ set_property(CACHE WITH_SOURCE_TREE PROPERTY STRINGS no flat hierarchical) # If disable - use c++17 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) diff --git a/src/cmake/showoptions.cmake b/src/cmake/showoptions.cmake index 8e8112140..906692e10 100644 --- a/src/cmake/showoptions.cmake +++ b/src/cmake/showoptions.cmake @@ -188,4 +188,12 @@ if (USE_CPP_20) message(" *** Please note that this is an experimental feature!") 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("") diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index 61e48cd94..e6cb945da 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -20,6 +20,7 @@ #include "StringConvert.h" #include "StringFormat.h" #include "Util.h" +#include "Tokenize.h" #include #include #include @@ -31,64 +32,82 @@ namespace std::vector _args; std::unordered_map _configOptions; std::mutex _configLock; + bool _usingDistConfig = false; // Check system configs like *server.conf* bool IsAppConfig(std::string_view fileName) { - size_t found = fileName.find_first_of("authserver.conf"); - if (found != std::string::npos) - { - return true; - } + size_t foundAuth = fileName.find("authserver.conf"); + size_t foundWorld = fileName.find("worldserver.conf"); - found = fileName.find_first_of("worldserver.conf"); - if (found != std::string::npos) - { - return true; - } + return foundAuth != std::string_view::npos || foundWorld != std::string_view::npos; + } - 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 inline void PrintError(std::string_view filename, Format&& fmt, Args&& ... args) { - std::string message = Acore::StringFormat(std::forward(fmt), std::forward(args)...); + std::string message = Acore::StringFormatFmt(std::forward(fmt), std::forward(args)...); if (IsAppConfig(filename)) { - printf("%s\n", message.c_str()); + fmt::print("{}\n", message); } 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); - 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; } + } + // Check exit option + if (itr != _configOptions.end()) + { _configOptions.erase(optionName); } _configOptions.emplace(optionName, optionKey); } - void ParseFile(std::string const& file) + bool ParseFile(std::string const& file, bool isOptional, bool isReload) { std::ifstream in(file); 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; @@ -100,7 +119,7 @@ namespace auto const& itr = fileConfigs.find(confOption); 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; } @@ -116,7 +135,7 @@ namespace // read line error 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 @@ -143,7 +162,7 @@ namespace 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; } @@ -166,43 +185,50 @@ namespace // No lines read 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 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 { - ParseFile(file); - return true; + return ParseFile(file, isOptional, isReload); } catch (const std::exception& e) { - PrintError(file, "> %s", e.what()); + PrintError(file, "> {}", e.what()); } return false; } } -bool ConfigMgr::LoadInitial(std::string const& file) +bool ConfigMgr::LoadInitial(std::string const& file, bool isReload /*= false*/) { std::lock_guard lock(_configLock); _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 lock(_configLock); - return LoadFile(file); + return LoadFile(file, isOptional, isReload); } ConfigMgr* ConfigMgr::instance() @@ -213,12 +239,12 @@ ConfigMgr* ConfigMgr::instance() bool ConfigMgr::Reload() { - if (!LoadAppConfigs()) + if (!LoadAppConfigs(true)) { return false; } - return LoadModulesConfigs(); + return LoadModulesConfigs(true, false); } template @@ -229,8 +255,8 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog { if (showLogs) { - LOG_ERROR("server.loading", "> Config: Missing name %s in config, add \"%s = %s\"", - name.c_str(), name.c_str(), Acore::ToString(def).c_str()); + FMT_LOG_ERROR("server.loading", "> Config: Missing property {} in all config files, at least the .dist file must contain: \"{} = {}\"", + name, name, Acore::ToString(def)); } return def; @@ -241,8 +267,8 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog { if (showLogs) { - LOG_ERROR("server.loading", "> Config: Bad value defined for name '%s', going to use '%s' instead", - name.c_str(), Acore::ToString(def).c_str()); + FMT_LOG_ERROR("server.loading", "> Config: Bad value defined for name '{}', going to use '{}' instead", + name, Acore::ToString(def)); } return def; @@ -259,8 +285,8 @@ std::string ConfigMgr::GetValueDefault(std::string const& name, std { if (showLogs) { - LOG_ERROR("server.loading", "> Config: Missing name %s in config, add \"%s = %s\"", - name.c_str(), name.c_str(), def.c_str()); + FMT_LOG_ERROR("server.loading", "> Config: Missing option {}, add \"{} = {}\"", + name, name, def); } return def; @@ -285,8 +311,8 @@ bool ConfigMgr::GetOption(std::string const& name, bool const& def, bool s { if (showLogs) { - LOG_ERROR("server.loading", "> Config: Bad value defined for name '%s', going to use '%s' instead", - name.c_str(), def ? "true" : "false"); + FMT_LOG_ERROR("server.loading", "> Config: Bad value defined for name '{}', going to use '{}' instead", + name, def ? "true" : "false"); } return def; @@ -302,18 +328,20 @@ std::vector ConfigMgr::GetKeysByString(std::string const& name) std::vector keys; for (auto const& [optionName, key] : _configOptions) + { if (!optionName.compare(0, name.length(), name)) { keys.emplace_back(optionName); } + } return keys; } -std::string const& ConfigMgr::GetFilename() +std::string const ConfigMgr::GetFilename() { std::lock_guard lock(_configLock); - return _filename; + return _usingDistConfig ? _filename + ".dist" : _filename; } std::vector const& ConfigMgr::GetArguments() const @@ -340,38 +368,44 @@ void ConfigMgr::Configure(std::string const& initFileName, std::vector ConfigMgr::LoadModulesConfigs: Not found original config '{}'. Stop loading", distFileName); + ABORT(); } // Load .conf config - if (!LoadAdditionalFile(moduleConfigPath + defaultFileName)) - { - isExistDefaultConfig = false; - } + isExistDefaultConfig = LoadAdditionalFile(moduleConfigPath + defaultFileName, true, isReload); if (isExistDefaultConfig && isExistDistConfig) { @@ -408,27 +442,32 @@ bool ConfigMgr::LoadModulesConfigs() } } - // If module configs not exist - no load - 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) + if (isNeedPrintInfo) { - 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", " "); + } -/* - * Deprecated geters. This geters will be deleted - */ + return true; +} // @deprecated DO NOT USE - use GetOption instead. 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(name, def, showLogs); } -/* - * End deprecated geters - */ - #define TEMPLATE_CONFIG_OPTION(__typename) \ template __typename ConfigMgr::GetOption<__typename>(std::string const& name, __typename const& def, bool showLogs /*= true*/) const; diff --git a/src/common/Configuration/Config.h b/src/common/Configuration/Config.h index 7eae1558a..9709a4f31 100644 --- a/src/common/Configuration/Config.h +++ b/src/common/Configuration/Config.h @@ -20,7 +20,7 @@ #include "Define.h" #include -#include +#include #include class ConfigMgr @@ -31,15 +31,15 @@ class ConfigMgr ~ConfigMgr() = default; public: - bool LoadAppConfigs(); - bool LoadModulesConfigs(); + bool LoadAppConfigs(bool isReload = false); + bool LoadModulesConfigs(bool isReload = false, bool isNeedPrintInfo = true); void Configure(std::string const& initFileName, std::vector args, std::string const& modulesConfigList = ""); static ConfigMgr* instance(); bool Reload(); - std::string const& GetFilename(); + std::string const GetFilename(); std::string const GetConfigPath(); std::vector const& GetArguments() const; std::vector GetKeysByString(std::string const& name); @@ -51,16 +51,16 @@ public: * Deprecated geters. This geters will be deleted */ - // @deprecated DO NOT USE - use GetOption instead. + [[deprecated("Use GetOption instead")]] std::string GetStringDefault(std::string const& name, const std::string& def, bool showLogs = true); - // @deprecated DO NOT USE - use GetOption instead. + [[deprecated("Use GetOption instead")]] bool GetBoolDefault(std::string const& name, bool def, bool showLogs = true); - // @deprecated DO NOT USE - use GetOption instead. + [[deprecated("Use GetOption instead")]] int GetIntDefault(std::string const& name, int def, bool showLogs = true); - // @deprecated DO NOT USE - use GetOption instead. + [[deprecated("Use GetOption instead")]] float GetFloatDefault(std::string const& name, float def, bool showLogs = true); /* @@ -70,12 +70,10 @@ public: bool isDryRun() { return dryRun; } void setDryRun(bool mode) { dryRun = mode; } - void PrintLoadedModulesConfigs(); - private: /// Method used only for loading main configuration files (authserver.conf and worldserver.conf) - bool LoadInitial(std::string const& file); - bool LoadAdditionalFile(std::string file); + bool LoadInitial(std::string const& file, bool isReload = false); + bool LoadAdditionalFile(std::string file, bool isOptional = false, bool isReload = false); template T GetValueDefault(std::string const& name, T const& def, bool showLogs = true) const; diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp index 2b0bfb520..05a5d6367 100644 --- a/src/common/Logging/Log.cpp +++ b/src/common/Logging/Log.cpp @@ -67,7 +67,7 @@ void Log::CreateAppenderFromConfig(std::string const& appenderName) // Format = type, level, flags, optional1, optional2 // if type = File. optional1 = file and option2 = mode // if type = Console. optional1 = Color - std::string options = sConfigMgr->GetStringDefault(appenderName, ""); + std::string options = sConfigMgr->GetOption(appenderName, ""); std::vector tokens = Acore::Tokenize(options, ',', true); @@ -130,7 +130,7 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName) LogLevel level = LOG_LEVEL_DISABLED; - std::string options = sConfigMgr->GetStringDefault(appenderName, ""); + std::string options = sConfigMgr->GetOption(appenderName, ""); std::string name = appenderName.substr(7); if (options.empty()) diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index b7398caf1..2118d8b9c 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -195,14 +195,11 @@ int main(int argc, char** argv) } // Add file and args in config - sConfigMgr->Configure(configFile, std::vector(argv, argv + argc), CONFIG_FILE_LIST); + sConfigMgr->Configure(configFile, { argv, argv + argc }, CONFIG_FILE_LIST); if (!sConfigMgr->LoadAppConfigs()) return 1; - // Loading modules configs - sConfigMgr->LoadModulesConfigs(); - std::shared_ptr ioContext = std::make_shared(); // Init all logs @@ -318,8 +315,8 @@ int main(int argc, char** argv) Acore::Module::SetEnableModulesList(AC_MODULES_LIST); - // Loading modules configs - sConfigMgr->PrintLoadedModulesConfigs(); + // Loading modules configs before scripts + sConfigMgr->LoadModulesConfigs(); ///- Initialize the World sSecretMgr->Initialize(); @@ -457,7 +454,7 @@ bool StartDB() return false; ///- Get the realm Id from the configuration file - realm.Id.Realm = sConfigMgr->GetIntDefault("RealmID", 0); + realm.Id.Realm = sConfigMgr->GetOption("RealmID", 0); if (!realm.Id.Realm) { LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");