diff options
| author | Stefan Boberg <[email protected]> | 2023-11-28 14:19:55 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-28 14:19:55 +0100 |
| commit | 76e0fe5d3bdb06691ee534954acdbaf56da0577d (patch) | |
| tree | 200d3dcdfe9b0f2dd14c2fb8c8650235fee890a0 /src/zenserver/config.cpp | |
| parent | tracing for gcv2 (#574) (diff) | |
| download | zen-76e0fe5d3bdb06691ee534954acdbaf56da0577d.tar.xz zen-76e0fe5d3bdb06691ee534954acdbaf56da0577d.zip | |
moved LuaConfig code so it can be used outside of config.cpp (#575)
Diffstat (limited to 'src/zenserver/config.cpp')
| -rw-r--r-- | src/zenserver/config.cpp | 645 |
1 files changed, 105 insertions, 540 deletions
diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp index 92d6c7f7d..fe92613f4 100644 --- a/src/zenserver/config.cpp +++ b/src/zenserver/config.cpp @@ -2,6 +2,7 @@ #include "config.h" +#include "config/luaconfig.h" #include "diag/logging.h" #include <zencore/crypto.h> @@ -175,592 +176,156 @@ MakeSafePath(const std::string_view Path) #endif }; -namespace LuaConfig { - - void EscapeBackslash(std::string& InOutString) - { - std::size_t BackslashPos = InOutString.find('\\'); - if (BackslashPos != std::string::npos) - { - std::size_t Offset = 0; - zen::ExtendableStringBuilder<512> PathBuilder; - while (BackslashPos != std::string::npos) - { - PathBuilder.Append(InOutString.substr(Offset, BackslashPos + 1 - Offset)); - PathBuilder.Append('\\'); - Offset = BackslashPos + 1; - BackslashPos = InOutString.find('\\', Offset); - } - PathBuilder.Append(InOutString.substr(Offset, BackslashPos)); - InOutString = PathBuilder.ToString(); +class CachePolicyOption : public LuaConfig::OptionValue +{ +public: + CachePolicyOption(UpstreamCachePolicy& Value) : Value(Value) {} + virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override + { + switch (Value) + { + case UpstreamCachePolicy::Read: + StringBuilder.Append("readonly"); + break; + case UpstreamCachePolicy::Write: + StringBuilder.Append("writeonly"); + break; + case UpstreamCachePolicy::Disabled: + StringBuilder.Append("disabled"); + break; + case UpstreamCachePolicy::ReadWrite: + StringBuilder.Append("readwrite"); + break; + default: + ZEN_ASSERT(false); } } - - class OptionValue - { - public: - virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) = 0; - virtual void Parse(sol::object Object) = 0; - - virtual ~OptionValue() {} - }; - - typedef std::shared_ptr<OptionValue> TOptionValue; - - class StringOption : public OptionValue + virtual void Parse(sol::object Object) override { - public: - StringOption(std::string& Value) : Value(Value) {} - virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override + std::string PolicyString = Object.as<std::string>(); + if (PolicyString == "readonly") { - StringBuilder.Append(fmt::format("\"{}\"", Value)); + Value = UpstreamCachePolicy::Read; } - virtual void Parse(sol::object Object) override { Value = Object.as<std::string>(); } - std::string& Value; - }; - - class FilePathOption : public OptionValue - { - public: - FilePathOption(std::filesystem::path& Value) : Value(Value) {} - virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override + else if (PolicyString == "writeonly") { - std::string Path = Value.string(); - EscapeBackslash(Path); - StringBuilder.Append(fmt::format("\"{}\"", Path)); + Value = UpstreamCachePolicy::Write; } - virtual void Parse(sol::object Object) override + else if (PolicyString == "disabled") { - std::string Str = Object.as<std::string>(); - if (!Str.empty()) - { - Value = MakeSafePath(Str); - } + Value = UpstreamCachePolicy::Disabled; } - std::filesystem::path& Value; - }; - - class BoolOption : public OptionValue - { - public: - BoolOption(bool& Value) : Value(Value) {} - virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override + else if (PolicyString == "readwrite") { - StringBuilder.Append(Value ? "true" : "false"); + Value = UpstreamCachePolicy::ReadWrite; } - virtual void Parse(sol::object Object) override { Value = Object.as<bool>(); } - bool& Value; - }; - - class CachePolicyOption : public OptionValue - { - public: - CachePolicyOption(UpstreamCachePolicy& Value) : Value(Value) {} - virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override - { - switch (Value) - { - case UpstreamCachePolicy::Read: - StringBuilder.Append("readonly"); - break; - case UpstreamCachePolicy::Write: - StringBuilder.Append("writeonly"); - break; - case UpstreamCachePolicy::Disabled: - StringBuilder.Append("disabled"); - break; - case UpstreamCachePolicy::ReadWrite: - StringBuilder.Append("readwrite"); - break; - default: - ZEN_ASSERT(false); - } - } - virtual void Parse(sol::object Object) override - { - std::string PolicyString = Object.as<std::string>(); - if (PolicyString == "readonly") - { - Value = UpstreamCachePolicy::Read; - } - else if (PolicyString == "writeonly") - { - Value = UpstreamCachePolicy::Write; - } - else if (PolicyString == "disabled") - { - Value = UpstreamCachePolicy::Disabled; - } - else if (PolicyString == "readwrite") - { - Value = UpstreamCachePolicy::ReadWrite; - } - } - UpstreamCachePolicy& Value; - }; - - template<Integral T> - class NumberOption : public OptionValue - { - public: - NumberOption(T& Value) : Value(Value) {} - virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override - { - StringBuilder.Append(fmt::format("{}", Value)); - } - virtual void Parse(sol::object Object) override { Value = Object.as<T>(); } - T& Value; - }; + } + UpstreamCachePolicy& Value; +}; - class LuaContainerWriter +class ZenAuthConfigOption : public LuaConfig::OptionValue +{ +public: + ZenAuthConfigOption(ZenAuthConfig& Value) : Value(Value) {} + virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override { - public: - LuaContainerWriter(zen::StringBuilderBase& StringBuilder, std::string_view Indent) - : StringBuilder(StringBuilder) - , InitialIndent(Indent.length()) - , LocalIndent(Indent) - { - StringBuilder.Append("{\n"); - LocalIndent.push_back('\t'); - } - ~LuaContainerWriter() + if (Value.OpenIdProviders.empty()) { - LocalIndent.pop_back(); - StringBuilder.Append(LocalIndent); - StringBuilder.Append("}"); + StringBuilder.Append("{}"); + return; } - - void BeginContainer(std::string_view Name) + LuaConfig::LuaContainerWriter Writer(StringBuilder, Indent); + for (const ZenOpenIdProviderConfig& Config : Value.OpenIdProviders) { - StringBuilder.Append(LocalIndent); - if (!Name.empty()) - { - StringBuilder.Append(Name); - StringBuilder.Append(" = {\n"); - } - else + Writer.BeginContainer(""); { - StringBuilder.Append("{\n"); + Writer.WriteValue("name", Config.Name); + Writer.WriteValue("url", Config.Url); + Writer.WriteValue("clientid", Config.ClientId); } - LocalIndent.push_back('\t'); + Writer.EndContainer(); } - void WriteValue(std::string_view Name, std::string_view Value) - { - if (Name.empty()) - { - StringBuilder.Append(fmt::format("{}\"{}\",\n", LocalIndent, Value)); - } - else - { - StringBuilder.Append(fmt::format("{}{} = \"{}\",\n", LocalIndent, Name, Value)); - } - } - void EndContainer() - { - LocalIndent.pop_back(); - StringBuilder.Append(LocalIndent); - StringBuilder.Append("}"); - StringBuilder.Append(",\n"); - } - - private: - zen::StringBuilderBase& StringBuilder; - const std::size_t InitialIndent; - std::string LocalIndent; - }; - - class StringArrayOption : public OptionValue + } + virtual void Parse(sol::object Object) override { - public: - StringArrayOption(std::vector<std::string>& Value) : Value(Value) {} - virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override + if (sol::optional<sol::table> OpenIdProviders = Object.as<sol::table>()) { - if (Value.empty()) - { - StringBuilder.Append("{}"); - } - if (Value.size() == 1) - { - StringBuilder.Append(fmt::format("\"{}\"", Value[0])); - } - else + for (const auto& Kv : OpenIdProviders.value()) { - LuaContainerWriter Writer(StringBuilder, Indent); - for (std::string String : Value) + if (sol::optional<sol::table> OpenIdProvider = Kv.second.as<sol::table>()) { - Writer.WriteValue("", String); - } - } - } - virtual void Parse(sol::object Object) override - { - if (Object.get_type() == sol::type::string) - { - Value.push_back(Object.as<std::string>()); - } - else if (Object.get_type() == sol::type::table) - { - for (const auto& Kv : Object.as<sol::table>()) - { - Value.push_back(Kv.second.as<std::string>()); - } - } - } - - private: - std::vector<std::string>& Value; - }; + std::string Name = OpenIdProvider.value().get_or("name", std::string("Default")); + std::string Url = OpenIdProvider.value().get_or("url", std::string()); + std::string ClientId = OpenIdProvider.value().get_or("clientid", std::string()); - class ZenAuthConfigOption : public OptionValue - { - public: - ZenAuthConfigOption(ZenAuthConfig& Value) : Value(Value) {} - virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override - { - if (Value.OpenIdProviders.empty()) - { - StringBuilder.Append("{}"); - return; - } - LuaContainerWriter Writer(StringBuilder, Indent); - for (const ZenOpenIdProviderConfig& Config : Value.OpenIdProviders) - { - Writer.BeginContainer(""); - { - Writer.WriteValue("name", Config.Name); - Writer.WriteValue("url", Config.Url); - Writer.WriteValue("clientid", Config.ClientId); + Value.OpenIdProviders.push_back({.Name = std::move(Name), .Url = std::move(Url), .ClientId = std::move(ClientId)}); } - Writer.EndContainer(); } } - virtual void Parse(sol::object Object) override - { - if (sol::optional<sol::table> OpenIdProviders = Object.as<sol::table>()) - { - for (const auto& Kv : OpenIdProviders.value()) - { - if (sol::optional<sol::table> OpenIdProvider = Kv.second.as<sol::table>()) - { - std::string Name = OpenIdProvider.value().get_or("name", std::string("Default")); - std::string Url = OpenIdProvider.value().get_or("url", std::string()); - std::string ClientId = OpenIdProvider.value().get_or("clientid", std::string()); - - Value.OpenIdProviders.push_back({.Name = std::move(Name), .Url = std::move(Url), .ClientId = std::move(ClientId)}); - } - } - } - } - ZenAuthConfig& Value; - }; + } + ZenAuthConfig& Value; +}; - class ZenObjectStoreConfigOption : public OptionValue +class ZenObjectStoreConfigOption : public LuaConfig::OptionValue +{ +public: + ZenObjectStoreConfigOption(ZenObjectStoreConfig& Value) : Value(Value) {} + virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override { - public: - ZenObjectStoreConfigOption(ZenObjectStoreConfig& Value) : Value(Value) {} - virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override + if (Value.Buckets.empty()) { - if (Value.Buckets.empty()) - { - StringBuilder.Append("{}"); - return; - } - LuaContainerWriter Writer(StringBuilder, Indent); - for (const ZenObjectStoreConfig::BucketConfig& Config : Value.Buckets) - { - Writer.BeginContainer(""); - { - Writer.WriteValue("name", Config.Name); - std::string Directory = Config.Directory.string(); - EscapeBackslash(Directory); - Writer.WriteValue("directory", Directory); - } - Writer.EndContainer(); - } + StringBuilder.Append("{}"); + return; } - virtual void Parse(sol::object Object) override + LuaConfig::LuaContainerWriter Writer(StringBuilder, Indent); + for (const ZenObjectStoreConfig::BucketConfig& Config : Value.Buckets) { - if (sol::optional<sol::table> Buckets = Object.as<sol::table>()) + Writer.BeginContainer(""); { - for (const auto& Kv : Buckets.value()) - { - if (sol::optional<sol::table> Bucket = Kv.second.as<sol::table>()) - { - std::string Name = Bucket.value().get_or("name", std::string("Default")); - std::string Directory = Bucket.value().get_or("directory", std::string()); - - Value.Buckets.push_back({.Name = std::move(Name), .Directory = MakeSafePath(Directory)}); - } - } + Writer.WriteValue("name", Config.Name); + std::string Directory = Config.Directory.string(); + LuaConfig::EscapeBackslash(Directory); + Writer.WriteValue("directory", Directory); } + Writer.EndContainer(); } - ZenObjectStoreConfig& Value; - }; - - std::shared_ptr<OptionValue> MakeOption(std::string& Value) { return std::make_shared<StringOption>(Value); }; - - std::shared_ptr<OptionValue> MakeOption(std::filesystem::path& Value) { return std::make_shared<FilePathOption>(Value); }; - - template<Integral T> - std::shared_ptr<OptionValue> MakeOption(T& Value) - { - return std::make_shared<NumberOption<T>>(Value); - }; - - std::shared_ptr<OptionValue> MakeOption(bool& Value) { return std::make_shared<BoolOption>(Value); }; - - std::shared_ptr<OptionValue> MakeOption(UpstreamCachePolicy& Value) { return std::make_shared<CachePolicyOption>(Value); }; - - std::shared_ptr<OptionValue> MakeOption(std::vector<std::string>& Value) { return std::make_shared<StringArrayOption>(Value); }; - - std::shared_ptr<OptionValue> MakeOption(ZenAuthConfig& Value) { return std::make_shared<ZenAuthConfigOption>(Value); }; - - std::shared_ptr<OptionValue> MakeOption(ZenObjectStoreConfig& Value) { return std::make_shared<ZenObjectStoreConfigOption>(Value); }; - - struct Option - { - std::string CommandLineOptionName; - TOptionValue Value; - }; - - struct Options + } + virtual void Parse(sol::object Object) override { - public: - template<typename T> - void AddOption(std::string_view Key, T& Value, std::string_view CommandLineOptionName = "") - { - OptionMap.insert_or_assign(std::string(Key), - Option{.CommandLineOptionName = std::string(CommandLineOptionName), .Value = MakeOption(Value)}); - }; - - void Parse(const std::filesystem::path& Path, const cxxopts::ParseResult& CmdLineResult) + if (sol::optional<sol::table> Buckets = Object.as<sol::table>()) { - zen::IoBuffer LuaScript = zen::IoBufferBuilder::MakeFromFile(Path); - - if (LuaScript) - { - sol::state lua; - - lua.open_libraries(sol::lib::base); - - lua.set_function("getenv", [&](const std::string env) -> sol::object { -#if ZEN_PLATFORM_WINDOWS - std::wstring EnvVarValue; - size_t RequiredSize = 0; - std::wstring EnvWide = zen::Utf8ToWide(env); - _wgetenv_s(&RequiredSize, nullptr, 0, EnvWide.c_str()); - - if (RequiredSize == 0) - return sol::make_object(lua, sol::lua_nil); - - EnvVarValue.resize(RequiredSize); - _wgetenv_s(&RequiredSize, EnvVarValue.data(), RequiredSize, EnvWide.c_str()); - return sol::make_object(lua, zen::WideToUtf8(EnvVarValue.c_str())); -#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC - char* EnvVariable = getenv(env.c_str()); - if (EnvVariable == nullptr) + for (const auto& Kv : Buckets.value()) { - return sol::make_object(lua, sol::lua_nil); - } - return sol::make_object(lua, EnvVariable); -#else - ZEN_UNUSED(env); - return sol::make_object(lua, sol::lua_nil); -#endif - }); - - try + if (sol::optional<sol::table> Bucket = Kv.second.as<sol::table>()) { - sol::load_result config = lua.load(std::string_view((const char*)LuaScript.Data(), LuaScript.Size()), "zen_cfg"); - - if (!config.valid()) - { - sol::error err = config; - - std::string ErrorString = sol::to_string(config.status()); - - throw std::runtime_error(fmt::format("{} error: {}", ErrorString, err.what())); - } + std::string Name = Bucket.value().get_or("name", std::string("Default")); + std::string Directory = Bucket.value().get_or("directory", std::string()); - config(); + Value.Buckets.push_back({.Name = std::move(Name), .Directory = LuaConfig::MakeSafePath(Directory)}); } - catch (std::exception& e) - { - throw std::runtime_error(fmt::format("failed to load config script ('{}'): {}", Path, e.what()).c_str()); - } - - Parse(lua, CmdLineResult); - } - } - - void Parse(const sol::state& LuaState, const cxxopts::ParseResult& CmdLineResult) - { - for (auto It : LuaState) - { - sol::object Key = It.first; - sol::type KeyType = Key.get_type(); - if (KeyType == sol::type::string) - { - sol::type ValueType = It.second.get_type(); - switch (ValueType) - { - case sol::type::table: - { - std::string Name = Key.as<std::string>(); - if (Name.starts_with("_")) - { - continue; - } - if (Name == "base") - { - continue; - } - Traverse(It.second.as<sol::table>(), Name, CmdLineResult); - } - break; - default: - break; - } - } - } - } - - void Touch(std::string_view Key) { UsedKeys.insert(std::string(Key)); } - - void Print(zen::StringBuilderBase& SB, const cxxopts::ParseResult& CmdLineResult) - { - for (auto It : OptionMap) - { - if (CmdLineResult.count(It.second.CommandLineOptionName) != 0) - { - UsedKeys.insert(It.first); - } - } - - std::vector<std::string> SortedKeys(UsedKeys.begin(), UsedKeys.end()); - std::sort(SortedKeys.begin(), SortedKeys.end()); - auto GetTablePath = [](const std::string& Key) -> std::vector<std::string> { - std::vector<std::string> Path; - zen::ForEachStrTok(Key, '.', [&Path](std::string_view Part) { - Path.push_back(std::string(Part)); - return true; - }); - return Path; - }; - std::vector<std::string> CurrentTablePath; - std::string Indent; - auto It = SortedKeys.begin(); - for (const std::string& Key : SortedKeys) - { - std::vector<std::string> KeyPath = GetTablePath(Key); - std::string Name = KeyPath.back(); - KeyPath.pop_back(); - if (CurrentTablePath != KeyPath) - { - size_t EqualCount = 0; - while (EqualCount < CurrentTablePath.size() && EqualCount < KeyPath.size() && - CurrentTablePath[EqualCount] == KeyPath[EqualCount]) - { - EqualCount++; - } - while (CurrentTablePath.size() > EqualCount) - { - CurrentTablePath.pop_back(); - Indent.pop_back(); - SB.Append(Indent); - SB.Append("}"); - if (CurrentTablePath.size() == EqualCount && !Indent.empty() && KeyPath.size() >= EqualCount) - { - SB.Append(","); - } - SB.Append("\n"); - if (Indent.empty()) - { - SB.Append("\n"); - } - } - while (EqualCount < KeyPath.size()) - { - SB.Append(Indent); - SB.Append(KeyPath[EqualCount]); - SB.Append(" = {\n"); - Indent.push_back('\t'); - CurrentTablePath.push_back(KeyPath[EqualCount]); - EqualCount++; - } - } - - SB.Append(Indent); - SB.Append(Name); - SB.Append(" = "); - OptionMap[Key].Value->Print(Indent, SB); - SB.Append(",\n"); - } - while (!CurrentTablePath.empty()) - { - Indent.pop_back(); - SB.Append(Indent); - SB.Append("}\n"); - CurrentTablePath.pop_back(); } } + } + ZenObjectStoreConfig& Value; +}; - private: - void Traverse(sol::table Table, std::string_view PathPrefix, const cxxopts::ParseResult& CmdLineResult) - { - for (auto It : Table) - { - sol::object Key = It.first; - sol::type KeyType = Key.get_type(); - if (KeyType == sol::type::string || KeyType == sol::type::number) - { - sol::type ValueType = It.second.get_type(); - switch (ValueType) - { - case sol::type::table: - case sol::type::string: - case sol::type::number: - case sol::type::boolean: - { - std::string Name = Key.as<std::string>(); - if (Name.starts_with("_")) - { - continue; - } - Name = std::string(PathPrefix) + "." + Key.as<std::string>(); - auto OptionIt = OptionMap.find(Name); - if (OptionIt != OptionMap.end()) - { - UsedKeys.insert(Name); - if (CmdLineResult.count(OptionIt->second.CommandLineOptionName) != 0) - { - continue; - } - OptionIt->second.Value->Parse(It.second); - continue; - } - if (ValueType == sol::type::table) - { - if (Name == "base") - { - continue; - } - Traverse(It.second.as<sol::table>(), Name, CmdLineResult); - } - } - break; - default: - break; - } - } - } - } +std::shared_ptr<LuaConfig::OptionValue> +MakeOption(zen::UpstreamCachePolicy& Value) +{ + return std::make_shared<CachePolicyOption>(Value); +}; - std::unordered_map<std::string, Option> OptionMap; - std::unordered_set<std::string> UsedKeys; - }; +std::shared_ptr<LuaConfig::OptionValue> +MakeOption(zen::ZenAuthConfig& Value) +{ + return std::make_shared<ZenAuthConfigOption>(Value); +}; -} // namespace LuaConfig +std::shared_ptr<LuaConfig::OptionValue> +MakeOption(zen::ZenObjectStoreConfig& Value) +{ + return std::make_shared<ZenObjectStoreConfigOption>(Value); +}; void ParseConfigFile(const std::filesystem::path& Path, |