aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver/config.cpp')
-rw-r--r--src/zenserver/config.cpp645
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,