23#include <boost/filesystem/directory.hpp>
24#include <boost/filesystem/operations.hpp>
25#include <boost/property_tree/ini_parser.hpp>
31namespace bpt = boost::property_tree;
36 std::string _filename;
37 std::vector<std::string> _additonalFiles;
38 std::vector<std::string> _args;
40 std::mutex _configLock;
42 bool LoadFile(std::string
const& file, bpt::ptree& fullTree, std::string& error)
46 bpt::ini_parser::read_ini(file, fullTree);
50 error =
"empty file (" + file +
")";
54 catch (bpt::ini_parser::ini_parser_error
const& e)
57 error = e.message() +
" (" + e.filename() +
")";
59 error = e.message() +
" (" + e.filename() +
":" + std::to_string(e.line()) +
")";
71 std::string IniKeyToEnvVarKey(std::string_view
const& key)
75 size_t n = key.length();
78 result.append(
"TC_"sv);
80 for (
size_t i = 0; i < n; ++i)
83 if (curr ==
' ' || curr ==
'.' || curr ==
'-')
89 bool isEnd = i == n - 1;
92 bool nextIsUpper = isupper(key[i + 1]);
95 if (!isupper(curr) && nextIsUpper)
103 bool nextIsNumeric =
isNumeric(key[i + 1]);
106 if (!currIsNumeric && nextIsNumeric)
114 if (currIsNumeric && !nextIsNumeric)
129 std::string envKey = IniKeyToEnvVarKey(key);
130 if (
char const* val = std::getenv(envKey.c_str()))
140 std::scoped_lock lock(_configLock);
142 _filename = std::move(file);
143 _args = std::move(args);
146 if (!LoadFile(_filename, fullTree, error))
150 _config = fullTree.begin()->second;
158 if (!LoadFile(file, fullTree, error))
161 std::scoped_lock lock(_configLock);
163 for (bpt::ptree::value_type
const& child : fullTree.begin()->second)
164 _config.put_child(bpt::ptree::path_type(child.first,
'/'), child.second);
167 _additonalFiles.emplace_back(std::move(file));
174 fs::path dirPath = dir;
175 if (!fs::exists(dirPath) || !fs::is_directory(dirPath))
178 for (fs::directory_entry
const& f : fs::recursive_directory_iterator(dirPath))
180 if (!fs::is_regular_file(f))
183 fs::path configFile = fs::absolute(f);
184 if (configFile.extension() !=
".conf")
187 std::string fileName = configFile.generic_string();
190 loadedFiles.push_back(std::move(fileName));
192 errors.push_back(std::move(error));
195 return errors.empty();
200 std::scoped_lock lock(_configLock);
202 std::vector<std::string> overriddenKeys;
204 for (bpt::ptree::value_type& itr: _config)
206 if (!itr.second.empty() || itr.first.empty())
213 itr.second = bpt::ptree(*envVar);
215 overriddenKeys.push_back(itr.first);
218 return overriddenKeys;
230 if (!
LoadInitial(_filename, std::move(_args), error))
231 errors.push_back(std::move(error));
233 for (std::string
const& additionalFile : _additonalFiles)
235 errors.push_back(std::move(error));
239 return errors.empty();
242template<
class T,
class R>
247 return _config.get<T>(bpt::ptree::path_type(std::string(name),
'/'));
249 catch (bpt::ptree_bad_path
const&)
253 Optional<T> castedVar = Trinity::StringTo<T>(*envVar);
256 TC_LOG_ERROR(
"server.loading",
"Bad value defined for name {} in environment variables, going to use default instead", name);
261 TC_LOG_WARN(
"server.loading",
"Missing name {} in config file {}, recovered with environment '{}' value.", name, _filename, *envVar);
267 TC_LOG_WARN(
"server.loading",
"Missing name {} in config file {}, add \"{} = {}\" to this file",
268 name, _filename, name, def);
271 catch (bpt::ptree_bad_data
const&)
273 TC_LOG_ERROR(
"server.loading",
"Bad value defined for name {} in config file {}, going to use {} instead",
274 name, _filename, def);
281std::string ConfigMgr::GetValueDefault<std::string_view>(std::string_view
const& name, std::string_view def,
bool quiet)
const
285 return _config.get<std::string>(bpt::ptree::path_type(std::string(name),
'/'));
287 catch (bpt::ptree_bad_path
const&)
292 TC_LOG_WARN(
"server.loading",
"Missing name {} in config file {}, recovered with environment '{}' value.", name, _filename, *envVar);
298 TC_LOG_WARN(
"server.loading",
"Missing name {} in config file {}, add \"{} = {}\" to this file",
299 name, _filename, name, def);
302 catch (bpt::ptree_bad_data
const&)
304 TC_LOG_ERROR(
"server.loading",
"Bad value defined for name {} in config file {}, going to use {} instead",
305 name, _filename, def);
308 return std::string(def);
313 std::string val = GetValueDefault<std::string_view, std::string>(name, def, quiet);
314 std::erase(val,
'"');
320 std::string val = GetValueDefault<std::string_view, std::string>(name, def ?
"1"sv :
"0"sv, quiet);
321 std::erase(val,
'"');
326 TC_LOG_ERROR(
"server.loading",
"Bad value defined for name {} in config file {}, going to use '{}' instead",
327 name, _filename, def ?
"true" :
"false");
349 std::scoped_lock lock(_configLock);
360 std::scoped_lock lock(_configLock);
362 std::vector<std::string> keys;
364 for (bpt::ptree::value_type
const& child : _config)
365 if (child.first.starts_with(name))
366 keys.push_back(child.first);
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_WARN(filterType__, message__,...)
std::optional< T > Optional
Optional helper class to wrap optional values within.
bool isNumeric(wchar_t wchar)
struct CharToUpper charToUpper
std::vector< std::string > OverrideWithEnvVariablesIfAny()
Overrides configuration with environment variables and returns overridden keys.
std::string const & GetFilename()
int32 GetIntDefault(std::string_view name, int32 def, bool quiet=false) const
int64 GetInt64Default(std::string_view name, int64 def, bool quiet=false) const
std::vector< std::string > GetKeysByString(std::string const &name)
std::string GetStringDefault(std::string_view name, std::string_view def, bool quiet=false) const
bool Reload(std::vector< std::string > &errors)
bool GetBoolDefault(std::string_view name, bool def, bool quiet=false) const
static ConfigMgr * instance()
bool LoadInitial(std::string file, std::vector< std::string > args, std::string &error)
Method used only for loading main configuration files (bnetserver.conf and worldserver....
std::vector< std::string > const & GetArguments() const
bool LoadAdditionalDir(std::string const &dir, bool keepOnReload, std::vector< std::string > &loadedFiles, std::vector< std::string > &errors)
float GetFloatDefault(std::string_view name, float def, bool quiet=false) const
bool LoadAdditionalFile(std::string file, bool keepOnReload, std::string &error)
R GetValueDefault(std::string_view const &name, T def, bool quiet) const