aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/vfs/vfsservice.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-09-20 15:22:03 +0200
committerGitHub <[email protected]>2023-09-20 15:22:03 +0200
commit14d7568f9c7d970b7bbf7b6463a0a8530f98bb6f (patch)
treebf24ac15759385cea339f7e1cf5380f984f5699a /src/zenserver/vfs/vfsservice.cpp
parentchangelog version bump (diff)
downloadzen-14d7568f9c7d970b7bbf7b6463a0a8530f98bb6f.tar.xz
zen-14d7568f9c7d970b7bbf7b6463a0a8530f98bb6f.zip
VFS implementation for local storage service (#396)
currently, only Windows (using Projected File System) is supported
Diffstat (limited to 'src/zenserver/vfs/vfsservice.cpp')
-rw-r--r--src/zenserver/vfs/vfsservice.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/zenserver/vfs/vfsservice.cpp b/src/zenserver/vfs/vfsservice.cpp
new file mode 100644
index 000000000..c53682d93
--- /dev/null
+++ b/src/zenserver/vfs/vfsservice.cpp
@@ -0,0 +1,217 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "vfsservice.h"
+#include "vfsimpl.h"
+
+#include <zencore/compactbinarybuilder.h>
+
+namespace zen {
+
+using namespace std::literals;
+
+#if ZEN_WITH_VFS
+
+//////////////////////////////////////////////////////////////////////////
+
+bool
+GetContentAsCbObject(HttpServerRequest& HttpReq, CbObject& Cb)
+{
+ IoBuffer Payload = HttpReq.ReadPayload();
+ HttpContentType PayloadContentType = HttpReq.RequestContentType();
+
+ switch (PayloadContentType)
+ {
+ case HttpContentType::kJSON:
+ case HttpContentType::kUnknownContentType:
+ case HttpContentType::kText:
+ {
+ std::string JsonText(reinterpret_cast<const char*>(Payload.GetData()), Payload.GetSize());
+ Cb = LoadCompactBinaryFromJson(JsonText).AsObject();
+ if (!Cb)
+ {
+ HttpReq.WriteResponse(HttpResponseCode::BadRequest,
+ HttpContentType::kText,
+ "Content format not supported, expected JSON format");
+ return false;
+ }
+ }
+ break;
+ case HttpContentType::kCbObject:
+ Cb = LoadCompactBinaryObject(Payload);
+ if (!Cb)
+ {
+ HttpReq.WriteResponse(HttpResponseCode::BadRequest,
+ HttpContentType::kText,
+ "Content format not supported, expected compact binary format");
+ return false;
+ }
+ break;
+ default:
+ HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid request content type");
+ return false;
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// to test:
+//
+// echo {"method": "mount", "params": {"path": "d:\\VFS_ROOT"}} | curl.exe http://localhost:1337/vfs --data-binary @-
+// echo {"method": "unmount"} | curl.exe http://localhost:1337/vfs --data-binary @-
+
+VfsService::VfsService()
+{
+ m_Impl = new Impl;
+
+ m_Router.RegisterRoute(
+ "info",
+ [&](HttpRouterRequest& Request) {
+ CbObjectWriter Cbo;
+ Cbo << "running" << m_Impl->IsVfsRunning();
+ Cbo << "rootpath" << m_Impl->GetMountpointPath();
+
+ Request.ServerRequest().WriteResponse(HttpResponseCode::OK, Cbo.Save());
+ },
+ HttpVerb::kGet | HttpVerb::kHead);
+
+ m_Router.RegisterRoute(
+ "",
+ [&](HttpRouterRequest& Req) {
+ CbObject Payload;
+
+ if (!GetContentAsCbObject(Req.ServerRequest(), Payload))
+ return;
+
+ std::string_view RpcName = Payload["method"sv].AsString();
+
+ if (RpcName == "mount"sv)
+ {
+ CbObjectView Params = Payload["params"sv].AsObjectView();
+ std::string_view Mountpath = Params["path"sv].AsString();
+
+ if (Mountpath.empty())
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "no path specified");
+ }
+
+ if (m_Impl->IsVfsRunning())
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "VFS already mounted");
+ }
+
+ try
+ {
+ m_Impl->Mount(Mountpath);
+ }
+ catch (std::exception& Ex)
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, Ex.what());
+ }
+
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK);
+ }
+ else if (RpcName == "unmount"sv)
+ {
+ if (!m_Impl->IsVfsRunning())
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "VFS not active");
+ }
+
+ try
+ {
+ m_Impl->Unmount();
+ }
+ catch (std::exception& Ex)
+ {
+ return Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, Ex.what());
+ }
+
+ Req.ServerRequest().WriteResponse(HttpResponseCode::OK);
+ }
+ else
+ {
+ Req.ServerRequest().WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "unknown RPC"sv);
+ }
+ },
+ HttpVerb::kPost);
+}
+
+VfsService::~VfsService()
+{
+ delete m_Impl;
+}
+
+void
+VfsService::Mount(std::string_view MountPoint)
+{
+ m_Impl->Mount(MountPoint);
+}
+
+void
+VfsService::Unmount()
+{
+ m_Impl->Unmount();
+}
+
+void
+VfsService::AddService(Ref<ProjectStore>&& Ps)
+{
+ m_Impl->AddService(std::move(Ps));
+}
+
+void
+VfsService::AddService(Ref<ZenCacheStore>&& Z$)
+{
+ m_Impl->AddService(std::move(Z$));
+}
+
+#else
+
+VfsService::VfsService()
+{
+}
+
+VfsService::~VfsService()
+{
+}
+
+void
+VfsService::Mount(std::string_view MountPoint)
+{
+ ZEN_UNUSED(MountPoint);
+}
+
+void
+VfsService::Unmount()
+{
+}
+
+void
+VfsService::AddService(Ref<ProjectStore>&& Ps)
+{
+ ZEN_UNUSED(Ps);
+}
+
+void
+VfsService::AddService(Ref<ZenCacheStore>&& Z$)
+{
+ ZEN_UNUSED(Z$);
+}
+
+#endif
+
+const char*
+VfsService::BaseUri() const
+{
+ return "/vfs/";
+}
+
+void
+VfsService::HandleRequest(HttpServerRequest& HttpServiceRequest)
+{
+ m_Router.HandleRequest(HttpServiceRequest);
+}
+
+} // namespace zen