From 2fca5545553bcb368096d27bd1f72cda99e52520 Mon Sep 17 00:00:00 2001 From: Смердокрыл Date: Fri, 9 Jun 2023 21:36:03 +0300 Subject: Core/Config: Implement reading config overrides from subdirectory (#29068) Co-authored-by: Shauren (cherry picked from commit 74a4dc46b49e1902f44a36b5b3155ad103d8f3da) --- src/common/Configuration/Config.cpp | 31 ++++++++++++++++++++++- src/common/Configuration/Config.h | 2 ++ src/server/authserver/CMakeLists.txt | 5 ++-- src/server/authserver/Main.cpp | 46 ++++++++++++++++++++++++++--------- src/server/worldserver/CMakeLists.txt | 5 ++-- src/server/worldserver/Main.cpp | 40 +++++++++++++++++++++--------- 6 files changed, 101 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index baf5d5bf11c..e8d7ebea477 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -18,7 +18,7 @@ #include "Config.h" #include "Log.h" #include "StringConvert.h" -#include "Util.h" +#include #include #include #include @@ -26,6 +26,7 @@ #include namespace bpt = boost::property_tree; +namespace fs = boost::filesystem; namespace { @@ -159,6 +160,8 @@ bool ConfigMgr::LoadAdditionalFile(std::string file, bool keepOnReload, std::str if (!LoadFile(file, fullTree, error)) return false; + std::lock_guard lock(_configLock); + for (bpt::ptree::value_type const& child : fullTree.begin()->second) _config.put_child(bpt::ptree::path_type(child.first, '/'), child.second); @@ -168,6 +171,32 @@ bool ConfigMgr::LoadAdditionalFile(std::string file, bool keepOnReload, std::str return true; } +bool ConfigMgr::LoadAdditionalDir(std::string const& dir, bool keepOnReload, std::vector& loadedFiles, std::vector& errors) +{ + fs::path dirPath = dir; + if (!fs::exists(dirPath) || !fs::is_directory(dirPath)) + return true; + + for (fs::directory_entry const& f : fs::recursive_directory_iterator(dirPath)) + { + if (!fs::is_regular_file(f)) + continue; + + fs::path configFile = fs::absolute(f); + if (configFile.extension() != ".conf") + continue; + + std::string fileName = configFile.generic_string(); + std::string error; + if (LoadAdditionalFile(fileName, keepOnReload, error)) + loadedFiles.push_back(std::move(fileName)); + else + errors.push_back(std::move(error)); + } + + return errors.empty(); +} + std::vector ConfigMgr::OverrideWithEnvVariablesIfAny() { std::lock_guard lock(_configLock); diff --git a/src/common/Configuration/Config.h b/src/common/Configuration/Config.h index 3e8dabe8ce3..0398506e9f9 100644 --- a/src/common/Configuration/Config.h +++ b/src/common/Configuration/Config.h @@ -20,6 +20,7 @@ #include "Define.h" #include +#include #include class TC_COMMON_API ConfigMgr @@ -33,6 +34,7 @@ public: /// Method used only for loading main configuration files (authserver.conf and worldserver.conf) bool LoadInitial(std::string file, std::vector args, std::string& error); bool LoadAdditionalFile(std::string file, bool keepOnReload, std::string& error); + bool LoadAdditionalDir(std::string const& dir, bool keepOnReload, std::vector& loadedFiles, std::vector& errors); /// Overrides configuration with environment variables and returns overridden keys std::vector OverrideWithEnvVariablesIfAny(); diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index 78995e39bd6..9a275efb840 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -35,8 +35,9 @@ add_executable(authserver ) if(NOT WIN32) - set_target_properties(authserver PROPERTIES - COMPILE_DEFINITIONS _TRINITY_REALM_CONFIG="${CONF_DIR}/authserver.conf" + target_compile_definitions(authserver PRIVATE + _TRINITY_REALM_CONFIG="${CONF_DIR}/authserver.conf" + _TRINITY_REALM_CONFIG_DIR="${CONF_DIR}/authserver.conf.d" ) endif() diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 1fc178b7dbd..d58c7a0c0c0 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -57,6 +57,9 @@ namespace fs = boost::filesystem; #ifndef _TRINITY_REALM_CONFIG # define _TRINITY_REALM_CONFIG "authserver.conf" #endif +#ifndef _TRINITY_REALM_CONFIG_DIR + #define _TRINITY_REALM_CONFIG_DIR "authserver.conf.d" +#endif #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS #include "ServiceWin32.h" @@ -79,7 +82,7 @@ void StopDB(); void SignalHandler(std::weak_ptr ioContextRef, boost::system::error_code const& error, int signalNumber); void KeepDatabaseAliveHandler(std::weak_ptr dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error); void BanExpiryHandler(std::weak_ptr banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error); -variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService); +variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, std::string& winServiceAction); int main(int argc, char** argv) { @@ -91,18 +94,19 @@ int main(int argc, char** argv) Trinity::Locale::Init(); auto configFile = fs::absolute(_TRINITY_REALM_CONFIG); - std::string configService; - auto vm = GetConsoleArguments(argc, argv, configFile, configService); + auto configDir = fs::absolute(_TRINITY_REALM_CONFIG_DIR); + std::string winServiceAction; + auto vm = GetConsoleArguments(argc, argv, configFile, configDir, winServiceAction); // exit if help or version is enabled if (vm.count("help") || vm.count("version")) return 0; #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS - if (configService.compare("install") == 0) + if (winServiceAction == "install") return WinServiceInstall() == true ? 0 : 1; - else if (configService.compare("uninstall") == 0) + if (winServiceAction == "uninstall") return WinServiceUninstall() == true ? 0 : 1; - else if (configService.compare("run") == 0) + if (winServiceAction == "run") return WinServiceRun() ? 0 : 1; #endif @@ -115,6 +119,20 @@ int main(int argc, char** argv) return 1; } + std::vector loadedConfigFiles; + std::vector configDirErrors; + bool additionalConfigFileLoadSuccess = sConfigMgr->LoadAdditionalDir(configDir.generic_string(), true, loadedConfigFiles, configDirErrors); + for (std::string const& loadedConfigFile : loadedConfigFiles) + printf("Loaded additional config file %s\n", loadedConfigFile.c_str()); + + if (!additionalConfigFileLoadSuccess) + { + for (std::string const& configDirError : configDirErrors) + printf("Error in additional config files: %s\n", configDirError.c_str()); + + return 1; + } + std::vector overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny(); sLog->RegisterAppender(); @@ -157,13 +175,16 @@ int main(int argc, char** argv) if (!StartDB()) return 1; + std::shared_ptr dbHandle(nullptr, [](void*) { StopDB(); }); + + if (vm.count("update-databases-only")) + return 0; + sSecretMgr->Initialize(); // Load IP Location Database sIPLocation->Load(); - std::shared_ptr dbHandle(nullptr, [](void*) { StopDB(); }); - std::shared_ptr ioContext = std::make_shared(); // Get the list of realms for the server @@ -325,7 +346,7 @@ void ServiceStatusWatcher(std::weak_ptr serviceSta } #endif -variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService) +variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, [[maybe_unused]] std::string& winServiceAction) { options_description all("Allowed options"); all.add_options() @@ -333,16 +354,17 @@ variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, s ("version,v", "print version build info") ("config,c", value(&configFile)->default_value(fs::absolute(_TRINITY_REALM_CONFIG)), "use as configuration file") + ("config-dir,cd", value(&configDir)->default_value(fs::absolute(_TRINITY_REALM_CONFIG_DIR)), + "use as directory with additional config files") + ("update-databases-only,u", "updates databases only") ; #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS options_description win("Windows platform specific options"); win.add_options() - ("service,s", value(&configService)->default_value(""), "Windows service options: [install | uninstall]") + ("service,s", value(&winServiceAction)->default_value(""), "Windows service options: [install | uninstall]") ; all.add(win); -#else - (void)configService; #endif variables_map variablesMap; try diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index f67a7a5b7fe..f723e777b4b 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -33,8 +33,9 @@ add_executable(worldserver ) if(NOT WIN32) - set_target_properties(worldserver PROPERTIES - COMPILE_DEFINITIONS _TRINITY_CORE_CONFIG="${CONF_DIR}/worldserver.conf" + target_compile_definitions(worldserver PRIVATE + _TRINITY_CORE_CONFIG="${CONF_DIR}/worldserver.conf" + _TRINITY_CORE_CONFIG_DIR="${CONF_DIR}/worldserver.conf.d" ) endif() diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index b9b74598a8f..70426698405 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -70,6 +70,10 @@ namespace fs = boost::filesystem; #define _TRINITY_CORE_CONFIG "worldserver.conf" #endif +#ifndef _TRINITY_CORE_CONFIG_DIR + #define _TRINITY_CORE_CONFIG_DIR "worldserver.conf.d" +#endif + #ifdef _WIN32 #include "ServiceWin32.h" char serviceName[] = "worldserver"; @@ -119,7 +123,7 @@ void WorldUpdateLoop(); void ClearOnlineAccounts(); void ShutdownCLIThread(std::thread* cliThread); bool LoadRealmInfo(Trinity::Asio::IoContext& ioContext); -variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService); +variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, std::string& winServiceAction); /// Launch the Trinity server extern int main(int argc, char** argv) @@ -132,19 +136,20 @@ extern int main(int argc, char** argv) Trinity::Locale::Init(); auto configFile = fs::absolute(_TRINITY_CORE_CONFIG); - std::string configService; + auto configDir = fs::absolute(_TRINITY_CORE_CONFIG_DIR); + std::string winServiceAction; - auto vm = GetConsoleArguments(argc, argv, configFile, configService); + auto vm = GetConsoleArguments(argc, argv, configFile, configDir, winServiceAction); // exit if help or version is enabled if (vm.count("help") || vm.count("version")) return 0; #ifdef _WIN32 - if (configService == "install") + if (winServiceAction == "install") return WinServiceInstall() ? 0 : 1; - else if (configService == "uninstall") + if (winServiceAction == "uninstall") return WinServiceUninstall() ? 0 : 1; - else if (configService == "run") + if (winServiceAction == "run") return WinServiceRun() ? 0 : 1; Optional newTimerResolution; @@ -195,6 +200,20 @@ extern int main(int argc, char** argv) return 1; } + std::vector loadedConfigFiles; + std::vector configDirErrors; + bool additionalConfigFileLoadSuccess = sConfigMgr->LoadAdditionalDir(configDir.generic_string(), true, loadedConfigFiles, configDirErrors); + for (std::string const& loadedConfigFile : loadedConfigFiles) + printf("Loaded additional config file %s\n", loadedConfigFile.c_str()); + + if (!additionalConfigFileLoadSuccess) + { + for (std::string const& configDirError : configDirErrors) + printf("Error in additional config files: %s\n", configDirError.c_str()); + + return 1; + } + std::vector overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny(); std::shared_ptr ioContext = std::make_shared(); @@ -689,23 +708,22 @@ void ClearOnlineAccounts() /// @} -variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService) +variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, [[maybe_unused]] std::string& winServiceAction) { - // Silences warning about configService not be used if the OS is not Windows - (void)configService; - options_description all("Allowed options"); all.add_options() ("help,h", "print usage message") ("version,v", "print version build info") ("config,c", value(&configFile)->default_value(fs::absolute(_TRINITY_CORE_CONFIG)), "use as configuration file") + ("config-dir,cd", value(&configDir)->default_value(fs::absolute(_TRINITY_CORE_CONFIG_DIR)), + "use as directory with additional config files") ("update-databases-only,u", "updates databases only") ; #ifdef _WIN32 options_description win("Windows platform specific options"); win.add_options() - ("service,s", value(&configService)->default_value(""), "Windows service options: [install | uninstall]") + ("service,s", value(&winServiceAction)->default_value(""), "Windows service options: [install | uninstall]") ; all.add(win); -- cgit v1.2.3