diff options
| author | Stefan Boberg <[email protected]> | 2023-12-11 13:09:03 +0100 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2023-12-11 13:09:03 +0100 |
| commit | 93afeddbc7a5b5df390a29407f5515acd5a70fc1 (patch) | |
| tree | 6f85ee551aabe20dece64a750c0b2d5d2c5d2d5d /src/zenserver/config.cpp | |
| parent | removed unnecessary SHA1 references (diff) | |
| parent | Make sure that PathFromHandle don't hide true error when throwing exceptions ... (diff) | |
| download | zen-93afeddbc7a5b5df390a29407f5515acd5a70fc1.tar.xz zen-93afeddbc7a5b5df390a29407f5515acd5a70fc1.zip | |
Merge branch 'main' of https://github.com/EpicGames/zen
Diffstat (limited to 'src/zenserver/config.cpp')
| -rw-r--r-- | src/zenserver/config.cpp | 729 |
1 files changed, 178 insertions, 551 deletions
diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp index 08ba6dc95..5f2c3351e 100644 --- a/src/zenserver/config.cpp +++ b/src/zenserver/config.cpp @@ -2,12 +2,14 @@ #include "config.h" +#include "config/luaconfig.h" #include "diag/logging.h" #include <zencore/crypto.h> #include <zencore/except.h> #include <zencore/fmtutils.h> #include <zencore/iobuffer.h> +#include <zencore/logging.h> #include <zencore/string.h> #include <zenhttp/zenhttp.h> #include <zenutil/basicfile.h> @@ -175,592 +177,156 @@ MakeSafePath(const std::string_view Path) #endif }; -namespace LuaConfig { - - void EscapeBackslash(std::string& InOutString) +class CachePolicyOption : public LuaConfig::OptionValue +{ +public: + CachePolicyOption(UpstreamCachePolicy& Value) : Value(Value) {} + virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override { - std::size_t BackslashPos = InOutString.find('\\'); - if (BackslashPos != std::string::npos) + switch (Value) { - 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(); + 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 - { - public: - StringOption(std::string& 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<std::string>(); } - std::string& Value; - }; - - class FilePathOption : public OptionValue + virtual void Parse(sol::object Object) override { - public: - FilePathOption(std::filesystem::path& Value) : Value(Value) {} - virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override + std::string PolicyString = Object.as<std::string>(); + if (PolicyString == "readonly") { - std::string Path = Value.string(); - EscapeBackslash(Path); - StringBuilder.Append(fmt::format("\"{}\"", Path)); + Value = UpstreamCachePolicy::Read; } - virtual void Parse(sol::object Object) override + else if (PolicyString == "writeonly") { - std::string Str = Object.as<std::string>(); - if (!Str.empty()) - { - Value = MakeSafePath(Str); - } + Value = UpstreamCachePolicy::Write; } - 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 == "disabled") { - StringBuilder.Append(Value ? "true" : "false"); + Value = UpstreamCachePolicy::Disabled; } - 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 + else if (PolicyString == "readwrite") { - 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); - } + Value = UpstreamCachePolicy::ReadWrite; } - 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) + if (Value.OpenIdProviders.empty()) { - StringBuilder.Append("{\n"); - LocalIndent.push_back('\t'); - } - ~LuaContainerWriter() - { - LocalIndent.pop_back(); - StringBuilder.Append(LocalIndent); - StringBuilder.Append("}"); - } - - void BeginContainer(std::string_view Name) - { - StringBuilder.Append(LocalIndent); - if (!Name.empty()) - { - StringBuilder.Append(Name); - StringBuilder.Append(" = {\n"); - } - else - { - StringBuilder.Append("{\n"); - } - LocalIndent.push_back('\t'); + StringBuilder.Append("{}"); + return; } - void WriteValue(std::string_view Name, std::string_view Value) + LuaConfig::LuaContainerWriter Writer(StringBuilder, Indent); + for (const ZenOpenIdProviderConfig& Config : Value.OpenIdProviders) { - if (Name.empty()) - { - StringBuilder.Append(fmt::format("{}\"{}\",\n", LocalIndent, Value)); - } - else + Writer.BeginContainer(""); { - StringBuilder.Append(fmt::format("{}{} = \"{}\",\n", LocalIndent, Name, Value)); + Writer.WriteValue("name", Config.Name); + Writer.WriteValue("url", Config.Url); + Writer.WriteValue("clientid", Config.ClientId); } + Writer.EndContainer(); } - 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 (Value.empty()) - { - StringBuilder.Append("{}"); - } - if (Value.size() == 1) - { - StringBuilder.Append(fmt::format("\"{}\"", Value[0])); - } - else - { - LuaContainerWriter Writer(StringBuilder, Indent); - for (std::string String : Value) - { - Writer.WriteValue("", String); - } - } - } - virtual void Parse(sol::object Object) override + if (sol::optional<sol::table> OpenIdProviders = Object.as<sol::table>()) { - if (Object.get_type() == sol::type::string) + for (const auto& Kv : OpenIdProviders.value()) { - Value.push_back(Object.as<std::string>()); - } - else if (Object.get_type() == sol::type::table) - { - for (const auto& Kv : Object.as<sol::table>()) + if (sol::optional<sol::table> OpenIdProvider = Kv.second.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); - } - 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)}); - } + 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) - { - 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) - { - 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 - { - 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())); - } - - config(); - } - 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) + if (sol::optional<sol::table> Buckets = Object.as<sol::table>()) { - for (auto It : OptionMap) + for (const auto& Kv : Buckets.value()) { - if (CmdLineResult.count(It.second.CommandLineOptionName) != 0) + if (sol::optional<sol::table> Bucket = Kv.second.as<sol::table>()) { - UsedKeys.insert(It.first); - } - } + std::string Name = Bucket.value().get_or("name", std::string("Default")); + std::string Directory = Bucket.value().get_or("directory", std::string()); - 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++; - } + Value.Buckets.push_back({.Name = std::move(Name), .Directory = LuaConfig::MakeSafePath(Directory)}); } - - 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, @@ -887,6 +453,10 @@ ParseConfigFile(const std::filesystem::path& Path, LuaOptions.AddOption("gc.lightweightntervalseconds"sv, ServerOptions.GcConfig.LightweightIntervalSeconds, "gc-lightweight-interval-seconds"sv); + LuaOptions.AddOption("gc.compactblockthreshold"sv, + ServerOptions.GcConfig.CompactBlockUsageThresholdPercent, + "gc-compactblock-threshold"sv); + LuaOptions.AddOption("gc.verbose"sv, ServerOptions.GcConfig.Verbose, "gc-verbose"sv); ////// gc LuaOptions.AddOption("gc.cache.maxdurationseconds"sv, ServerOptions.GcConfig.Cache.MaxDurationSeconds, "gc-cache-duration-seconds"sv); @@ -938,6 +508,7 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) std::string AbsLogFile; std::string ConfigFile; std::string OutputConfigFile; + std::string BaseSnapshotDir; cxxopts::Options options("zenserver", "Zen Server"); options.add_options()("dedicated", @@ -947,12 +518,20 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) options.add_options()("clean", "Clean out all state at startup", cxxopts::value<bool>(ServerOptions.IsCleanStart)->default_value("false")); + options.add_options()("scrub", + "Validate state at startup", + cxxopts::value(ServerOptions.ScrubOptions)->implicit_value("yes"), + "(nocas,nogc,nodelete,yes,no)*"); options.add_options()("help", "Show command line help"); options.add_options()("t, test", "Enable test mode", cxxopts::value<bool>(ServerOptions.IsTest)->default_value("false")); - options.add_options()("log-id", "Specify id for adding context to log output", cxxopts::value<std::string>(ServerOptions.LogId)); options.add_options()("data-dir", "Specify persistence root", cxxopts::value<std::string>(DataDir)); + options.add_options()("snapshot-dir", + "Specify a snapshot of server state to mirror into the persistence root at startup", + cxxopts::value<std::string>(BaseSnapshotDir)); options.add_options()("content-dir", "Frontend content directory", cxxopts::value<std::string>(ContentDir)); - options.add_options()("abslog", "Path to log file", cxxopts::value<std::string>(AbsLogFile)); + options.add_options()("powercycle", + "Exit immediately after initialization is complete", + cxxopts::value<bool>(ServerOptions.IsPowerCycle)); options.add_options()("config", "Path to Lua config file", cxxopts::value<std::string>(ConfigFile)); options.add_options()("write-config", "Path to output Lua config file", cxxopts::value<std::string>(OutputConfigFile)); options.add_options()("no-sentry", @@ -961,7 +540,21 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) options.add_options()("sentry-allow-personal-info", "Allow personally identifiable information in sentry crash reports", cxxopts::value<bool>(ServerOptions.SentryAllowPII)->default_value("false")); - options.add_options()("quiet", "Disable console logging", cxxopts::value<bool>(ServerOptions.NoConsoleOutput)->default_value("false")); + + // clang-format off + options.add_options("logging") + ("abslog", "Path to log file", cxxopts::value<std::string>(AbsLogFile)) + ("log-id", "Specify id for adding context to log output", cxxopts::value<std::string>(ServerOptions.LogId)) + ("quiet", "Disable console logging", cxxopts::value<bool>(ServerOptions.NoConsoleOutput)->default_value("false")) + ("log-trace", "Change selected loggers to level TRACE", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Trace])) + ("log-debug", "Change selected loggers to level DEBUG", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Debug])) + ("log-info", "Change selected loggers to level INFO", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Info])) + ("log-warn", "Change selected loggers to level WARN", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Warn])) + ("log-error", "Change selected loggers to level ERROR", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Err])) + ("log-critical", "Change selected loggers to level CRITICAL", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Critical])) + ("log-off", "Change selected loggers to level OFF", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Off])) + ; + // clang-format on options.add_option("security", "", @@ -1313,6 +906,21 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) cxxopts::value<uint64_t>(ServerOptions.GcConfig.DiskSizeSoftLimit)->default_value("0"), ""); + options.add_option("gc", + "", + "gc-compactblock-threshold", + "Garbage collection - how much of a compact block should be used to skip compacting the block. 0 - compact only " + "empty eligible blocks, 100 - compact all non-full eligible blocks.", + cxxopts::value<uint32_t>(ServerOptions.GcConfig.CompactBlockUsageThresholdPercent)->default_value("60"), + ""); + + options.add_option("gc", + "", + "gc-verbose", + "Enable verbose logging for GC.", + cxxopts::value<bool>(ServerOptions.GcConfig.Verbose)->default_value("false"), + ""); + options.add_option("objectstore", "", "objectstore-enabled", @@ -1337,9 +945,18 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) try { - auto result = options.parse(argc, argv); + cxxopts::ParseResult Result; - if (result.count("help")) + try + { + Result = options.parse(argc, argv); + } + catch (std::exception& Ex) + { + throw zen::OptionParseException(Ex.what()); + } + + if (Result.count("help")) { ZEN_CONSOLE("{}", options.help()); #if ZEN_PLATFORM_WINDOWS @@ -1352,12 +969,28 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) exit(0); } + for (int i = 0; i < logging::level::LogLevelCount; ++i) + { + logging::ConfigureLogLevels(logging::level::LogLevel(i), ServerOptions.Loggers[i]); + } + logging::RefreshLogLevels(); + ServerOptions.DataDir = MakeSafePath(DataDir); + ServerOptions.BaseSnapshotDir = MakeSafePath(BaseSnapshotDir); ServerOptions.ContentDir = MakeSafePath(ContentDir); ServerOptions.AbsLogFile = MakeSafePath(AbsLogFile); ServerOptions.ConfigFile = MakeSafePath(ConfigFile); ServerOptions.UpstreamCacheConfig.CachePolicy = ParseUpstreamCachePolicy(UpstreamCachePolicyOptions); + if (!BaseSnapshotDir.empty()) + { + if (DataDir.empty()) + throw zen::OptionParseException("You must explicitly specify a data directory when specifying a base snapshot"); + + if (!std::filesystem::is_directory(ServerOptions.BaseSnapshotDir)) + throw OptionParseException(fmt::format("Snapshot directory must be a directory: '{}", BaseSnapshotDir)); + } + if (OpenIdProviderUrl.empty() == false) { if (OpenIdClientId.empty()) @@ -1373,21 +1006,15 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions) if (!ServerOptions.ConfigFile.empty()) { - ParseConfigFile(ServerOptions.ConfigFile, ServerOptions, result, OutputConfigFile); + ParseConfigFile(ServerOptions.ConfigFile, ServerOptions, Result, OutputConfigFile); } else { - ParseConfigFile(ServerOptions.DataDir / "zen_cfg.lua", ServerOptions, result, OutputConfigFile); + ParseConfigFile(ServerOptions.DataDir / "zen_cfg.lua", ServerOptions, Result, OutputConfigFile); } ValidateOptions(ServerOptions); } - catch (cxxopts::OptionParseException& e) - { - ZEN_CONSOLE_ERROR("Error parsing zenserver arguments: {}\n\n{}", e.what(), options.help()); - - throw; - } catch (zen::OptionParseException& e) { ZEN_CONSOLE_ERROR("Error parsing zenserver arguments: {}\n\n{}", e.what(), options.help()); |