aboutsummaryrefslogtreecommitdiff
path: root/zenserver/zenserver.cpp
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2021-10-20 13:19:39 +0200
committerMartin Ridgers <[email protected]>2021-10-20 13:19:39 +0200
commit13feae57532a1ad4d14feb5ee00f397fa6c370cc (patch)
tree4bfdfe0aa239435baddef9ee64965c39ec7f6551 /zenserver/zenserver.cpp
parentCompile fixes due to std::fs::path's differing character types (diff)
parentzen server: Added root manifest, with support for explicit schema versioning (diff)
downloadzen-13feae57532a1ad4d14feb5ee00f397fa6c370cc.tar.xz
zen-13feae57532a1ad4d14feb5ee00f397fa6c370cc.zip
Merged main
Diffstat (limited to 'zenserver/zenserver.cpp')
-rw-r--r--zenserver/zenserver.cpp117
1 files changed, 101 insertions, 16 deletions
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index c9b52604d..269db7394 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -1,6 +1,7 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include <zencore/compactbinarybuilder.h>
+#include <zencore/compactbinaryvalidation.h>
#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
#include <zencore/iobuffer.h>
@@ -40,6 +41,8 @@ ZEN_THIRD_PARTY_INCLUDES_END
# define BUILD_VERSION ("dev-build")
#endif
+#define ZEN_SCHEMA_VERSION 1
+
//////////////////////////////////////////////////////////////////////////
// We don't have any doctest code in this file but this is needed to bring
// in some shared code into the executable
@@ -154,6 +157,78 @@ public:
throw std::runtime_error("Failed to create mutex '{}' - is another instance already running?"_format(MutexName).c_str());
}
+ // Check root manifest to deal with schema versioning
+
+ bool WipeState = false;
+ std::string WipeReason = "Unspecified";
+
+ std::filesystem::path ManifestPath = m_DataRoot / "root_manifest";
+ FileContents ManifestData = zen::ReadFile(ManifestPath);
+
+ if (ManifestData.ErrorCode)
+ {
+ WipeState = true;
+ WipeReason = "No manifest present at '{}'"_format(ManifestPath);
+ }
+ else
+ {
+ IoBuffer Manifest = ManifestData.Flatten();
+
+ if (CbValidateError ValidationResult = ValidateCompactBinary(Manifest, CbValidateMode::All);
+ ValidationResult != CbValidateError::None)
+ {
+ ZEN_ERROR("Manifest validation failed: {}, state will be wiped", ValidationResult);
+
+ WipeState = true;
+ WipeReason = "Validation of manifest at '{}' failed: {}"_format(ManifestPath, ValidationResult);
+ }
+ else
+ {
+ m_RootManifest = LoadCompactBinaryObject(Manifest);
+
+ const int32_t ManifestVersion = m_RootManifest["schema_version"].AsInt32(0);
+
+ if (ManifestVersion != ZEN_SCHEMA_VERSION)
+ {
+ WipeState = true;
+ WipeReason = "Manifest schema version: {}, differs from required: {}"_format(ManifestVersion, ZEN_SCHEMA_VERSION);
+ }
+ }
+ }
+
+ // Handle any state wipe
+
+ if (WipeState)
+ {
+ ZEN_WARN("Wiping state at '{}' - reason: '{}'", m_DataRoot, WipeReason);
+
+ std::error_code Ec;
+ for (const std::filesystem::directory_entry& DirEntry : std::filesystem::directory_iterator{m_DataRoot, Ec})
+ {
+ if (DirEntry.is_directory())
+ {
+ ZEN_INFO("Deleting '{}'", DirEntry.path());
+
+ std::filesystem::remove_all(DirEntry.path(), Ec);
+
+ if (Ec)
+ {
+ ZEN_WARN("Delete of '{}' returned error: '{}'", DirEntry.path(), Ec.message());
+ }
+ }
+ }
+
+ ZEN_INFO("Wiped all directories in data root");
+
+ // Write new manifest
+
+ CbObjectWriter Cbo;
+ Cbo << "schema_version" << ZEN_SCHEMA_VERSION;
+ m_RootManifest = Cbo.Save();
+
+ WriteFile(ManifestPath, m_RootManifest.GetBuffer().AsIoBuffer());
+ }
+
// Ok so now we're configured, let's kick things off
m_Http = zen::CreateHttpServer(HttpServerClass);
@@ -409,6 +484,7 @@ private:
ZenServerState::ZenServerEntry* m_ServerEntry = nullptr;
bool m_IsDedicatedMode = false;
bool m_TestMode = false;
+ CbObject m_RootManifest;
std::filesystem::path m_DataRoot;
std::filesystem::path m_ContentRoot;
std::jthread m_IoRunner;
@@ -693,27 +769,36 @@ main(int argc, char* argv[])
mi_version();
#endif
- ZenServerOptions GlobalOptions;
- ZenServiceConfig ServiceConfig;
- ParseGlobalCliOptions(argc, argv, GlobalOptions, ServiceConfig);
- InitializeLogging(GlobalOptions);
+ try
+ {
+ ZenServerOptions GlobalOptions;
+ ZenServiceConfig ServiceConfig;
+ ParseGlobalCliOptions(argc, argv, GlobalOptions, ServiceConfig);
+ InitializeLogging(GlobalOptions);
#if ZEN_PLATFORM_WINDOWS
- if (GlobalOptions.InstallService)
- {
- WindowsService::Install();
+ if (GlobalOptions.InstallService)
+ {
+ WindowsService::Install();
- std::exit(0);
- }
+ std::exit(0);
+ }
- if (GlobalOptions.UninstallService)
- {
- WindowsService::Delete();
+ if (GlobalOptions.UninstallService)
+ {
+ WindowsService::Delete();
- std::exit(0);
- }
+ std::exit(0);
+ }
#endif
- ZenWindowsService App(GlobalOptions, ServiceConfig);
- return App.ServiceMain();
+ ZenWindowsService App(GlobalOptions, ServiceConfig);
+ return App.ServiceMain();
+ }
+ catch (std::exception& Ex)
+ {
+ fprintf(stderr, "ERROR: Caught exception in main: '%s'", Ex.what());
+
+ return 1;
+ }
}