aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/workspaces/httpworkspaces.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-10-14 11:32:16 +0200
committerGitHub Enterprise <[email protected]>2025-10-14 11:32:16 +0200
commitca09abbeef5b1788f4a52b61eedd2f3dd07f81f2 (patch)
tree005a50adfddf6982bab3a06bb93d4c50da1a11fd /src/zenserver/workspaces/httpworkspaces.cpp
parentmake asiohttp work without IPv6 (#562) (diff)
downloadzen-ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2.tar.xz
zen-ca09abbeef5b1788f4a52b61eedd2f3dd07f81f2.zip
move all storage-related services into storage tree (#571)
* move all storage-related services into storage tree * move config into config/ * also move admin service into storage since it mostly has storage related functionality * header consolidation
Diffstat (limited to 'src/zenserver/workspaces/httpworkspaces.cpp')
-rw-r--r--src/zenserver/workspaces/httpworkspaces.cpp1211
1 files changed, 0 insertions, 1211 deletions
diff --git a/src/zenserver/workspaces/httpworkspaces.cpp b/src/zenserver/workspaces/httpworkspaces.cpp
deleted file mode 100644
index 7ef84743e..000000000
--- a/src/zenserver/workspaces/httpworkspaces.cpp
+++ /dev/null
@@ -1,1211 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include <workspaces/httpworkspaces.h>
-
-#include <zencore/basicfile.h>
-#include <zencore/compactbinarybuilder.h>
-#include <zencore/fmtutils.h>
-#include <zencore/logging.h>
-#include <zencore/trace.h>
-#include <zenstore/workspaces.h>
-#include <zenutil/chunkrequests.h>
-#include <zenutil/workerpools.h>
-
-#include <unordered_set>
-
-namespace zen {
-using namespace std::literals;
-
-ZEN_DEFINE_LOG_CATEGORY_STATIC(LogFs, "fs"sv);
-
-namespace {
-
- std::filesystem::path GetPathParameter(HttpServerRequest& ServerRequest, std::string_view Name)
- {
- if (std::string_view Value = ServerRequest.GetQueryParams().GetValue(Name); !Value.empty())
- {
- return std::filesystem::path(HttpServerRequest::Decode(Value));
- }
- return {};
- }
-
- void WriteWorkspaceConfig(CbWriter& Writer, const Workspaces::WorkspaceConfiguration& Config)
- {
- Writer << "id" << Config.Id;
- Writer << "root_path" << Config.RootPath.string(); // utf8?
- Writer << "allow_share_creation_from_http" << Config.AllowShareCreationFromHttp;
- };
-
- void WriteWorkspaceShareConfig(CbWriter& Writer, const Workspaces::WorkspaceShareConfiguration& Config)
- {
- Writer << "id" << Config.Id;
- Writer << "share_path" << Config.SharePath.string(); // utf8?
- if (!Config.Alias.empty())
- {
- Writer << "alias" << Config.Alias;
- }
- };
-
- void WriteWorkspaceAndSharesConfig(CbWriter& Writer, Workspaces& Workspaces, const Workspaces::WorkspaceConfiguration& WorkspaceConfig)
- {
- WriteWorkspaceConfig(Writer, WorkspaceConfig);
- if (std::optional<std::vector<Oid>> ShareIds = Workspaces.GetWorkspaceShares(WorkspaceConfig.Id); ShareIds)
- {
- Writer.BeginArray("shares");
- {
- for (const Oid& ShareId : *ShareIds)
- {
- if (std::optional<Workspaces::WorkspaceShareConfiguration> WorkspaceShareConfig =
- Workspaces.GetWorkspaceShareConfiguration(WorkspaceConfig.Id, ShareId);
- WorkspaceShareConfig)
- {
- Writer.BeginObject();
- {
- WriteWorkspaceShareConfig(Writer, *WorkspaceShareConfig);
- }
- Writer.EndObject();
- }
- }
- }
- Writer.EndArray();
- }
- }
-
-} // namespace
-
-HttpWorkspacesService::HttpWorkspacesService(HttpStatusService& StatusService,
- HttpStatsService& StatsService,
- const WorkspacesServeConfig& Cfg,
- Workspaces& Workspaces)
-: m_Log(logging::Get("workspaces"))
-, m_StatusService(StatusService)
-, m_StatsService(StatsService)
-, m_Config(Cfg)
-, m_Workspaces(Workspaces)
-{
- Initialize();
-}
-
-HttpWorkspacesService::~HttpWorkspacesService()
-{
- m_StatsService.UnregisterHandler("ws", *this);
- m_StatusService.UnregisterHandler("ws", *this);
-}
-
-const char*
-HttpWorkspacesService::BaseUri() const
-{
- return "/ws/";
-}
-
-void
-HttpWorkspacesService::HandleRequest(HttpServerRequest& Request)
-{
- metrics::OperationTiming::Scope $(m_HttpRequests);
-
- if (m_Router.HandleRequest(Request) == false)
- {
- ZEN_LOG_WARN(LogFs, "No route found for {0}", Request.RelativeUri());
- return Request.WriteResponse(HttpResponseCode::NotFound, HttpContentType::kText, "Not found"sv);
- }
-}
-
-void
-HttpWorkspacesService::HandleStatsRequest(HttpServerRequest& HttpReq)
-{
- ZEN_TRACE_CPU("WorkspacesService::Stats");
- CbObjectWriter Cbo;
-
- EmitSnapshot("requests", m_HttpRequests, Cbo);
-
- Cbo.BeginObject("workspaces");
- {
- Cbo.BeginObject("workspace");
- {
- Cbo << "readcount" << m_WorkspacesStats.WorkspaceReadCount << "writecount" << m_WorkspacesStats.WorkspaceWriteCount
- << "deletecount" << m_WorkspacesStats.WorkspaceDeleteCount;
- }
- Cbo.EndObject();
-
- Cbo.BeginObject("workspaceshare");
- {
- Cbo << "readcount" << m_WorkspacesStats.WorkspaceShareReadCount << "writecount" << m_WorkspacesStats.WorkspaceShareWriteCount
- << "deletecount" << m_WorkspacesStats.WorkspaceShareDeleteCount;
- }
- Cbo.EndObject();
-
- Cbo.BeginObject("chunk");
- {
- Cbo << "hitcount" << m_WorkspacesStats.WorkspaceShareChunkHitCount << "misscount"
- << m_WorkspacesStats.WorkspaceShareChunkMissCount;
- }
- Cbo.EndObject();
-
- Cbo << "filescount" << m_WorkspacesStats.WorkspaceShareFilesReadCount;
- Cbo << "entriescount" << m_WorkspacesStats.WorkspaceShareEntriesReadCount;
- Cbo << "batchcount" << m_WorkspacesStats.WorkspaceShareBatchReadCount;
-
- Cbo << "requestcount" << m_WorkspacesStats.RequestCount;
- Cbo << "badrequestcount" << m_WorkspacesStats.BadRequestCount;
- }
- Cbo.EndObject();
-
- return HttpReq.WriteResponse(HttpResponseCode::OK, Cbo.Save());
-}
-
-void
-HttpWorkspacesService::HandleStatusRequest(HttpServerRequest& Request)
-{
- ZEN_TRACE_CPU("HttpWorkspacesService::Status");
- CbObjectWriter Cbo;
- Cbo << "ok" << true;
- Request.WriteResponse(HttpResponseCode::OK, Cbo.Save());
-}
-
-void
-HttpWorkspacesService::Initialize()
-{
- using namespace std::literals;
-
- ZEN_LOG_INFO(LogFs, "Initializing Workspaces Service");
-
- m_Router.AddPattern("workspace_id", "([[:xdigit:]]{24})");
- m_Router.AddPattern("share_id", "([[:xdigit:]]{24})");
- m_Router.AddPattern("chunk", "([[:xdigit:]]{24})");
- m_Router.AddPattern("share_alias", "([[:alnum:]_.\\+\\-\\[\\]]+)");
-
- m_Router.RegisterRoute(
- "{workspace_id}/{share_id}/files",
- [this](HttpRouterRequest& Req) { FilesRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "{workspace_id}/{share_id}/{chunk}/info",
- [this](HttpRouterRequest& Req) { ChunkInfoRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "{workspace_id}/{share_id}/batch",
- [this](HttpRouterRequest& Req) { BatchRequest(Req); },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "{workspace_id}/{share_id}/entries",
- [this](HttpRouterRequest& Req) { EntriesRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "{workspace_id}/{share_id}/{chunk}",
- [this](HttpRouterRequest& Req) { ChunkRequest(Req); },
- HttpVerb::kGet | HttpVerb::kHead);
-
- m_Router.RegisterRoute(
- "share/{share_alias}/files",
- [this](HttpRouterRequest& Req) { ShareAliasFilesRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "share/{share_alias}/{chunk}/info",
- [this](HttpRouterRequest& Req) { ShareAliasChunkInfoRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "share/{share_alias}/batch",
- [this](HttpRouterRequest& Req) { ShareAliasBatchRequest(Req); },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "share/{share_alias}/entries",
- [this](HttpRouterRequest& Req) { ShareAliasEntriesRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "share/{share_alias}/{chunk}",
- [this](HttpRouterRequest& Req) { ShareAliasChunkRequest(Req); },
- HttpVerb::kGet | HttpVerb::kHead);
-
- m_Router.RegisterRoute(
- "share/{share_alias}",
- [this](HttpRouterRequest& Req) { ShareAliasRequest(Req); },
- HttpVerb::kPut | HttpVerb::kGet | HttpVerb::kDelete);
-
- m_Router.RegisterRoute(
- "{workspace_id}/{share_id}",
- [this](HttpRouterRequest& Req) { ShareRequest(Req); },
- HttpVerb::kPut | HttpVerb::kGet | HttpVerb::kDelete);
-
- m_Router.RegisterRoute(
- "{workspace_id}",
- [this](HttpRouterRequest& Req) { WorkspaceRequest(Req); },
- HttpVerb::kPut | HttpVerb::kGet | HttpVerb::kDelete);
-
- m_Router.RegisterRoute(
- "refresh",
- [this](HttpRouterRequest& Req) { RefreshRequest(Req); },
- HttpVerb::kGet);
-
- m_Router.RegisterRoute(
- "",
- [this](HttpRouterRequest& Req) { WorkspacesRequest(Req); },
- HttpVerb::kGet);
-
- RefreshState();
-
- m_StatsService.RegisterHandler("ws", *this);
- m_StatusService.RegisterHandler("ws", *this);
-}
-
-std::filesystem::path
-HttpWorkspacesService::GetStatePath() const
-{
- return m_Config.SystemRootDir / "workspaces";
-}
-
-void
-HttpWorkspacesService::RefreshState()
-{
- if (!m_Config.SystemRootDir.empty())
- {
- m_Workspaces.RefreshState(GetStatePath());
- }
-}
-
-bool
-HttpWorkspacesService::MayChangeConfiguration(const HttpServerRequest& Req) const
-{
- ZEN_UNUSED(Req);
- return m_Config.AllowConfigurationChanges;
-}
-
-void
-HttpWorkspacesService::RefreshRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- RefreshState();
- return ServerRequest.WriteResponse(HttpResponseCode::OK);
-}
-
-void
-HttpWorkspacesService::WorkspacesRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
-
- std::vector<Oid> WorkspaceIds = m_Workspaces.GetWorkspaces();
- CbObjectWriter Response;
- Response.BeginArray("workspaces");
- for (const Oid& WorkspaceId : WorkspaceIds)
- {
- if (std::optional<Workspaces::WorkspaceConfiguration> WorkspaceConfig = m_Workspaces.GetWorkspaceConfiguration(WorkspaceId);
- WorkspaceConfig)
- {
- Response.BeginObject();
- {
- WriteWorkspaceAndSharesConfig(Response, m_Workspaces, *WorkspaceConfig);
- }
- Response.EndObject();
- }
- }
- Response.EndArray();
-
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response.Save());
-}
-
-void
-HttpWorkspacesService::FilesRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- const Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- const Oid ShareId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", Req.GetCapture(2)));
- }
- FilesRequest(Req, WorkspaceId, ShareId);
-}
-
-void
-HttpWorkspacesService::ChunkInfoRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- const Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- const Oid ShareId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", Req.GetCapture(2)));
- }
- const Oid ChunkId = Oid::TryFromHexString(Req.GetCapture(3));
- if (ChunkId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid chunk id '{}'", Req.GetCapture(3)));
- }
- ChunkInfoRequest(Req, WorkspaceId, ShareId, ChunkId);
-}
-
-void
-HttpWorkspacesService::BatchRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- const Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- const Oid ShareId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", Req.GetCapture(2)));
- }
- BatchRequest(Req, WorkspaceId, ShareId);
-}
-
-void
-HttpWorkspacesService::EntriesRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- const Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- const Oid ShareId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", Req.GetCapture(2)));
- }
- EntriesRequest(Req, WorkspaceId, ShareId);
-}
-
-void
-HttpWorkspacesService::ChunkRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- const Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- const Oid ShareId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", Req.GetCapture(2)));
- }
- const Oid ChunkId = Oid::TryFromHexString(Req.GetCapture(3));
- if (ChunkId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid chunk id '{}'", Req.GetCapture(3)));
- }
- ChunkRequest(Req, WorkspaceId, ShareId, ChunkId);
-}
-
-void
-HttpWorkspacesService::ShareRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- const Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- Oid ShareId = Oid::Zero;
- if (Req.GetCapture(2) != Oid::Zero.ToString())
- {
- ShareId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", Req.GetCapture(2)));
- }
- }
- ShareRequest(Req, WorkspaceId, ShareId);
-}
-
-void
-HttpWorkspacesService::WorkspaceRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- Oid WorkspaceId = Oid::TryFromHexString(Req.GetCapture(1));
- switch (ServerRequest.RequestVerb())
- {
- case HttpVerb::kPut:
- {
- std::filesystem::path WorkspacePath = GetPathParameter(ServerRequest, "root_path"sv);
- if (WorkspacePath.empty())
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- "Invalid 'root_path' parameter");
- }
-
- if (Req.GetCapture(1) == Oid::Zero.ToString())
- {
- // Synthesize Id
- WorkspaceId = Workspaces::PathToId(WorkspacePath);
- ZEN_INFO("Generated workspace id from path '{}': {}", WorkspacePath, WorkspaceId);
- }
- else if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
-
- if (!MayChangeConfiguration(ServerRequest))
- {
- return ServerRequest.WriteResponse(HttpResponseCode::Unauthorized,
- HttpContentType::kText,
- fmt::format("Adding workspace {} is not allowed", WorkspaceId));
- }
- bool AllowShareCreationFromHttp = false;
- if (std::string_view Value = ServerRequest.GetQueryParams().GetValue("allow_share_creation_from_http"); Value == "true"sv)
- {
- AllowShareCreationFromHttp = true;
- }
-
- m_WorkspacesStats.WorkspaceWriteCount++;
- Workspaces::WorkspaceConfiguration OldConfig = Workspaces::FindWorkspace(Log(), GetStatePath(), WorkspaceId);
- Workspaces::WorkspaceConfiguration NewConfig = {.Id = WorkspaceId,
- .RootPath = WorkspacePath,
- .AllowShareCreationFromHttp = AllowShareCreationFromHttp};
- if (OldConfig.Id == WorkspaceId && (OldConfig != NewConfig))
- {
- return ServerRequest.WriteResponse(
- HttpResponseCode::Conflict,
- HttpContentType::kText,
- fmt::format("Workspace {} already exists with root path '{}'", WorkspaceId, OldConfig.RootPath));
- }
- else if (OldConfig.Id == Oid::Zero)
- {
- if (Workspaces::WorkspaceConfiguration ConfigWithSameRoot =
- Workspaces::FindWorkspace(Log(), GetStatePath(), WorkspacePath);
- ConfigWithSameRoot.Id != Oid::Zero)
- {
- return ServerRequest.WriteResponse(
- HttpResponseCode::Conflict,
- HttpContentType::kText,
- fmt::format("Workspace {} already exists with same root path '{}'", ConfigWithSameRoot.Id, WorkspacePath));
- }
- }
-
- bool Created = Workspaces::AddWorkspace(Log(), GetStatePath(), NewConfig);
- if (Created)
- {
- ZEN_ASSERT(OldConfig.Id == Oid::Zero);
- RefreshState();
- return ServerRequest.WriteResponse(HttpResponseCode::Created, HttpContentType::kText, fmt::format("{}", WorkspaceId));
- }
- else
- {
- return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, fmt::format("{}", WorkspaceId));
- }
- }
- case HttpVerb::kGet:
- {
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- m_WorkspacesStats.WorkspaceReadCount++;
- std::optional<Workspaces::WorkspaceConfiguration> Workspace = m_Workspaces.GetWorkspaceConfiguration(WorkspaceId);
- if (Workspace)
- {
- CbObjectWriter Response;
- WriteWorkspaceAndSharesConfig(Response, m_Workspaces, *Workspace);
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response.Save());
- }
- else
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- }
- case HttpVerb::kDelete:
- {
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
-
- if (!MayChangeConfiguration(ServerRequest))
- {
- return ServerRequest.WriteResponse(HttpResponseCode::Unauthorized,
- HttpContentType::kText,
- fmt::format("Removing workspace {} is not allowed", WorkspaceId));
- }
-
- m_WorkspacesStats.WorkspaceDeleteCount++;
- bool Deleted = Workspaces::RemoveWorkspace(Log(), GetStatePath(), WorkspaceId);
- if (Deleted)
- {
- RefreshState();
- return ServerRequest.WriteResponse(HttpResponseCode::OK);
- }
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- }
-}
-
-void
-HttpWorkspacesService::ShareAliasFilesRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view Alias = Req.GetCapture(1);
- if (Alias.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid alias '{}'", Req.GetCapture(1)));
- }
- std::optional<Workspaces::ShareAlias> WorkspaceAndShareId = m_Workspaces.GetShareAlias(Alias);
- if (!WorkspaceAndShareId.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- FilesRequest(Req, WorkspaceAndShareId.value().WorkspaceId, WorkspaceAndShareId.value().ShareId);
-}
-
-void
-HttpWorkspacesService::ShareAliasChunkInfoRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view Alias = Req.GetCapture(1);
- if (Alias.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid alias '{}'", Req.GetCapture(1)));
- }
- std::optional<Workspaces::ShareAlias> WorkspaceAndShareId = m_Workspaces.GetShareAlias(Alias);
- if (!WorkspaceAndShareId.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- const Oid ChunkId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ChunkId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid chunk id '{}'", Req.GetCapture(2)));
- }
- ChunkInfoRequest(Req, WorkspaceAndShareId.value().WorkspaceId, WorkspaceAndShareId.value().ShareId, ChunkId);
-}
-
-void
-HttpWorkspacesService::ShareAliasBatchRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view Alias = Req.GetCapture(1);
- if (Alias.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid alias '{}'", Req.GetCapture(1)));
- }
- std::optional<Workspaces::ShareAlias> WorkspaceAndShareId = m_Workspaces.GetShareAlias(Alias);
- if (!WorkspaceAndShareId.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- BatchRequest(Req, WorkspaceAndShareId.value().WorkspaceId, WorkspaceAndShareId.value().ShareId);
-}
-
-void
-HttpWorkspacesService::ShareAliasEntriesRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view Alias = Req.GetCapture(1);
- if (Alias.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid alias '{}'", Req.GetCapture(1)));
- }
- std::optional<Workspaces::ShareAlias> WorkspaceAndShareId = m_Workspaces.GetShareAlias(Alias);
- if (!WorkspaceAndShareId.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- EntriesRequest(Req, WorkspaceAndShareId.value().WorkspaceId, WorkspaceAndShareId.value().ShareId);
-}
-
-void
-HttpWorkspacesService::ShareAliasChunkRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view Alias = Req.GetCapture(1);
- if (Alias.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid alias '{}'", Req.GetCapture(1)));
- }
- std::optional<Workspaces::ShareAlias> WorkspaceAndShareId = m_Workspaces.GetShareAlias(Alias);
- if (!WorkspaceAndShareId.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- const Oid ChunkId = Oid::TryFromHexString(Req.GetCapture(2));
- if (ChunkId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid chunk id '{}'", Req.GetCapture(2)));
- }
- ChunkRequest(Req, WorkspaceAndShareId.value().WorkspaceId, WorkspaceAndShareId.value().ShareId, ChunkId);
-}
-
-void
-HttpWorkspacesService::ShareAliasRequest(HttpRouterRequest& Req)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view Alias = Req.GetCapture(1);
- if (Alias.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid alias '{}'", Req.GetCapture(1)));
- }
- std::optional<Workspaces::ShareAlias> WorkspaceAndShareId = m_Workspaces.GetShareAlias(Alias);
- if (!WorkspaceAndShareId.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- ShareRequest(Req, WorkspaceAndShareId.value().WorkspaceId, WorkspaceAndShareId.value().ShareId);
-}
-
-void
-HttpWorkspacesService::FilesRequest(HttpRouterRequest& Req, const Oid& WorkspaceId, const Oid& ShareId)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
-
- m_WorkspacesStats.WorkspaceShareFilesReadCount++;
-
- std::unordered_set<std::string> WantedFieldNames;
- if (auto FieldFilter = HttpServerRequest::Decode(ServerRequest.GetQueryParams().GetValue("fieldnames")); !FieldFilter.empty())
- {
- if (FieldFilter != "*") // Get all - empty FieldFilter equal getting all fields
- {
- ForEachStrTok(FieldFilter, ',', [&](std::string_view FieldName) {
- WantedFieldNames.insert(std::string(FieldName));
- return true;
- });
- }
- }
- else
- {
- const bool FilterClient = ServerRequest.GetQueryParams().GetValue("filter"sv) == "client"sv;
- WantedFieldNames.insert("id");
- WantedFieldNames.insert("clientpath");
- if (!FilterClient)
- {
- WantedFieldNames.insert("serverpath");
- }
- }
-
- bool Refresh = false;
- if (auto RefreshStr = ServerRequest.GetQueryParams().GetValue("refresh"); !RefreshStr.empty())
- {
- Refresh = StrCaseCompare(std::string(RefreshStr).c_str(), "true") == 0;
- }
-
- const bool WantsAllFields = WantedFieldNames.empty();
-
- const bool WantsIdField = WantsAllFields || WantedFieldNames.contains("id");
- const bool WantsClientPathField = WantsAllFields || WantedFieldNames.contains("clientpath");
- const bool WantsServerPathField = WantsAllFields || WantedFieldNames.contains("serverpath");
- const bool WantsRawSizeField = WantsAllFields || WantedFieldNames.contains("rawsize");
- const bool WantsSizeField = WantsAllFields || WantedFieldNames.contains("size");
-
- std::optional<std::vector<Workspaces::ShareFile>> Files =
- m_Workspaces.GetWorkspaceShareFiles(WorkspaceId, ShareId, Refresh, GetSmallWorkerPool(EWorkloadType::Burst));
- if (!Files.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
-
- CbObjectWriter Response;
- Response.BeginArray("files"sv);
- {
- for (const Workspaces::ShareFile& Entry : Files.value())
- {
- Response.BeginObject();
- if (WantsIdField)
- {
- Response << "id"sv << Entry.Id;
- }
- if (WantsServerPathField)
- {
- Response << "serverpath"sv << Entry.RelativePath;
- }
- if (WantsClientPathField)
- {
- Response << "clientpath"sv << Entry.RelativePath;
- }
- if (WantsSizeField)
- {
- Response << "size"sv << Entry.Size;
- }
- if (WantsRawSizeField)
- {
- Response << "rawsize"sv << Entry.Size;
- }
- Response.EndObject();
- }
- }
- Response.EndArray();
-
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response.Save());
-}
-
-void
-HttpWorkspacesService::ChunkInfoRequest(HttpRouterRequest& Req, const Oid& WorkspaceId, const Oid& ShareId, const Oid& ChunkId)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- Workspaces::ShareFile File =
- m_Workspaces.GetWorkspaceShareChunkInfo(WorkspaceId, ShareId, ChunkId, GetSmallWorkerPool(EWorkloadType::Burst));
- if (File.Id != Oid::Zero)
- {
- CbObjectWriter Response;
- Response << "size"sv << File.Size;
- m_WorkspacesStats.WorkspaceShareChunkHitCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response.Save());
- }
- m_WorkspacesStats.WorkspaceShareChunkMissCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
-}
-
-void
-HttpWorkspacesService::BatchRequest(HttpRouterRequest& Req, const Oid& WorkspaceId, const Oid& ShareId)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- IoBuffer Payload = ServerRequest.ReadPayload();
- std::optional<std::vector<RequestChunkEntry>> ChunkRequests = ParseChunkBatchRequest(Payload);
- if (!ChunkRequests.has_value())
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "batch payload malformed");
- }
- m_WorkspacesStats.WorkspaceShareBatchReadCount++;
- std::vector<Workspaces::ChunkRequest> Requests;
- Requests.reserve(ChunkRequests.value().size());
- std::transform(ChunkRequests.value().begin(),
- ChunkRequests.value().end(),
- std::back_inserter(Requests),
- [](const RequestChunkEntry& Entry) {
- return Workspaces::ChunkRequest{.ChunkId = Entry.ChunkId, .Offset = Entry.Offset, .Size = Entry.RequestBytes};
- });
- std::vector<IoBuffer> Chunks =
- m_Workspaces.GetWorkspaceShareChunks(WorkspaceId, ShareId, Requests, GetSmallWorkerPool(EWorkloadType::Burst));
- if (Chunks.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- for (const IoBuffer& Buffer : Chunks)
- {
- if (Buffer)
- {
- m_WorkspacesStats.WorkspaceShareChunkHitCount++;
- }
- else
- {
- m_WorkspacesStats.WorkspaceShareChunkMissCount++;
- }
- }
- std::vector<IoBuffer> Response = BuildChunkBatchResponse(ChunkRequests.value(), Chunks);
- if (!Response.empty())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kBinary, Response);
- }
- return ServerRequest.WriteResponse(HttpResponseCode::InternalServerError,
- HttpContentType::kText,
- fmt::format("failed formatting response for batch of {} chunks", Chunks.size()));
-}
-
-void
-HttpWorkspacesService::EntriesRequest(HttpRouterRequest& Req, const Oid& WorkspaceId, const Oid& ShareId)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string_view OpKey = ServerRequest.GetQueryParams().GetValue("opkey"sv);
- if (!OpKey.empty() && OpKey != "file_manifest")
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- std::unordered_set<std::string> WantedFieldNames;
- if (auto FieldFilter = HttpServerRequest::Decode(ServerRequest.GetQueryParams().GetValue("fieldfilter")); !FieldFilter.empty())
- {
- if (FieldFilter != "*") // Get all - empty FieldFilter equal getting all fields
- {
- ForEachStrTok(FieldFilter, ',', [&](std::string_view FieldName) {
- WantedFieldNames.insert(std::string(FieldName));
- return true;
- });
- }
- }
-
- bool Refresh = false;
- if (auto RefreshStr = ServerRequest.GetQueryParams().GetValue("refresh"); !RefreshStr.empty())
- {
- Refresh = StrCaseCompare(std::string(RefreshStr).c_str(), "true") == 0;
- }
-
- m_WorkspacesStats.WorkspaceShareEntriesReadCount++;
- std::optional<std::vector<Workspaces::ShareFile>> Files =
- m_Workspaces.GetWorkspaceShareFiles(WorkspaceId, ShareId, Refresh, GetSmallWorkerPool(EWorkloadType::Burst));
- if (!Files.has_value())
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- const bool WantsAllFields = WantedFieldNames.empty();
-
- const bool WantsIdField = WantsAllFields || WantedFieldNames.contains("id");
- const bool WantsClientPathField = WantsAllFields || WantedFieldNames.contains("clientpath");
- const bool WantsServerPathField = WantsAllFields || WantedFieldNames.contains("serverpath");
-
- CbObjectWriter Response;
-
- if (OpKey.empty())
- {
- Response.BeginArray("entries"sv);
- Response.BeginObject();
- }
- else
- {
- Response.BeginObject("entry"sv);
- }
- {
- // Synthesize a fake op
- Response << "key"
- << "file_manifest";
-
- Response.BeginArray("files");
- {
- for (const Workspaces::ShareFile& Entry : Files.value())
- {
- Response.BeginObject();
- {
- if (WantsIdField)
- {
- Response << "id"sv << Entry.Id;
- }
- if (WantsServerPathField)
- {
- Response << "serverpath"sv << Entry.RelativePath;
- }
- if (WantsClientPathField)
- {
- Response << "clientpath"sv << Entry.RelativePath;
- }
- }
- Response.EndObject();
- }
- }
- Response.EndArray();
- }
-
- if (OpKey.empty())
- {
- Response.EndObject();
- Response.EndArray();
- }
- else
- {
- Response.EndObject();
- }
-
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response.Save());
-}
-
-void
-HttpWorkspacesService::ChunkRequest(HttpRouterRequest& Req, const Oid& WorkspaceId, const Oid& ShareId, const Oid& ChunkId)
-{
- HttpServerRequest& ServerRequest = Req.ServerRequest();
-
- uint64_t Offset = 0;
- uint64_t Size = ~(0ull);
- if (auto OffsetParm = ServerRequest.GetQueryParams().GetValue("offset"); OffsetParm.empty() == false)
- {
- if (auto OffsetVal = ParseInt<uint64_t>(OffsetParm))
- {
- Offset = OffsetVal.value();
- }
- else
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid offset parameter '{}'", OffsetParm));
- }
- }
-
- if (auto SizeParm = ServerRequest.GetQueryParams().GetValue("size"); SizeParm.empty() == false)
- {
- if (auto SizeVal = ParseInt<uint64_t>(SizeParm))
- {
- Size = SizeVal.value();
- }
- else
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid size parameter '{}'", SizeParm));
- }
- }
-
- std::vector<IoBuffer> Response = m_Workspaces.GetWorkspaceShareChunks(
- WorkspaceId,
- ShareId,
- std::vector<Workspaces::ChunkRequest>{Workspaces::ChunkRequest{.ChunkId = ChunkId, .Offset = Offset, .Size = Size}},
- GetSmallWorkerPool(EWorkloadType::Burst));
- if (!Response.empty() && Response[0])
- {
- m_WorkspacesStats.WorkspaceShareChunkHitCount++;
- if (Response[0].GetSize() == 0)
- {
- return ServerRequest.WriteResponse(HttpResponseCode::OK);
- }
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response[0].GetContentType(), Response);
- }
- m_WorkspacesStats.WorkspaceShareChunkMissCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
-}
-
-void
-HttpWorkspacesService::ShareRequest(HttpRouterRequest& Req, const Oid& WorkspaceId, const Oid& InShareId)
-{
- Oid ShareId = InShareId;
-
- HttpServerRequest& ServerRequest = Req.ServerRequest();
- switch (ServerRequest.RequestVerb())
- {
- case HttpVerb::kPut:
- {
- std::filesystem::path SharePath = GetPathParameter(ServerRequest, "share_path"sv);
- if (SharePath.empty())
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- "Invalid 'share_path' parameter");
- }
-
- if (ShareId == Oid::Zero)
- {
- // Synthesize Id
- ShareId = Workspaces::PathToId(SharePath);
- ZEN_INFO("Generated workspace id from path '{}': {}", SharePath, ShareId);
- }
-
- std::string Alias = HttpServerRequest::Decode(ServerRequest.GetQueryParams().GetValue("alias"sv));
- if (!AsciiSet::HasOnly(Alias, Workspaces::ValidAliasCharactersSet))
- {
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid 'alias' parameter");
- }
-
- Workspaces::WorkspaceConfiguration Workspace = Workspaces::FindWorkspace(Log(), GetStatePath(), WorkspaceId);
- if (Workspace.Id == Oid::Zero)
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound,
- HttpContentType::kText,
- fmt::format("Workspace '{}' does not exist", WorkspaceId));
- }
-
- if (!Workspace.AllowShareCreationFromHttp)
- {
- if (!MayChangeConfiguration(ServerRequest))
- {
- return ServerRequest.WriteResponse(
- HttpResponseCode::Unauthorized,
- HttpContentType::kText,
- fmt::format("Adding workspace share {} in workspace {} is not allowed", WorkspaceId, ShareId));
- }
- }
-
- m_WorkspacesStats.WorkspaceShareWriteCount++;
-
- const Workspaces::WorkspaceShareConfiguration OldConfig =
- Workspaces::FindWorkspaceShare(Log(), Workspace.RootPath, ShareId);
- const Workspaces::WorkspaceShareConfiguration NewConfig = {.Id = ShareId,
- .SharePath = SharePath,
- .Alias = std::string(Alias)};
-
- if (OldConfig.Id == ShareId && (OldConfig != NewConfig))
- {
- return ServerRequest.WriteResponse(
- HttpResponseCode::Conflict,
- HttpContentType::kText,
- fmt::format("Workspace share '{}' already exist in workspace '{}' with share path '{}' and alias '{}'",
- ShareId,
- WorkspaceId,
- OldConfig.SharePath,
- OldConfig.Alias));
- }
- else if (OldConfig.Id == Oid::Zero)
- {
- if (Workspaces::WorkspaceShareConfiguration ConfigWithSamePath =
- Workspaces::FindWorkspaceShare(Log(), Workspace.RootPath, SharePath);
- ConfigWithSamePath.Id != Oid::Zero)
- {
- return ServerRequest.WriteResponse(
- HttpResponseCode::Conflict,
- HttpContentType::kText,
- fmt::format("Workspace share '{}' already exist in workspace '{}' with same share path '{}' and alias '{}'",
- ShareId,
- WorkspaceId,
- OldConfig.SharePath,
- OldConfig.Alias));
- }
- }
-
- if (!IsDir(Workspace.RootPath / NewConfig.SharePath))
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound,
- HttpContentType::kText,
- fmt::format("directory {} does not exist in workspace {} root '{}'",
- NewConfig.SharePath,
- WorkspaceId,
- Workspace.RootPath));
- }
-
- bool Created = Workspaces::AddWorkspaceShare(Log(), Workspace.RootPath, NewConfig);
- if (Created)
- {
- RefreshState();
- return ServerRequest.WriteResponse(HttpResponseCode::Created, HttpContentType::kText, fmt::format("{}", ShareId));
- }
- return ServerRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, fmt::format("{}", ShareId));
- }
- case HttpVerb::kGet:
- {
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", ShareId));
- }
-
- m_WorkspacesStats.WorkspaceShareReadCount++;
- std::optional<Workspaces::WorkspaceShareConfiguration> Config =
- m_Workspaces.GetWorkspaceShareConfiguration(WorkspaceId, ShareId);
- if (!Config)
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
-
- CbObjectWriter Response;
- WriteWorkspaceShareConfig(Response, *Config);
- return ServerRequest.WriteResponse(HttpResponseCode::OK, Response.Save());
- }
- case HttpVerb::kDelete:
- {
- if (WorkspaceId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid workspace id '{}'", Req.GetCapture(1)));
- }
- if (ShareId == Oid::Zero)
- {
- m_WorkspacesStats.BadRequestCount++;
- return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
- HttpContentType::kText,
- fmt::format("Invalid share id '{}'", ShareId));
- }
-
- Workspaces::WorkspaceConfiguration Workspace = Workspaces::FindWorkspace(Log(), GetStatePath(), WorkspaceId);
- if (Workspace.Id == Oid::Zero)
- {
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
-
- if (!Workspace.AllowShareCreationFromHttp)
- {
- if (!MayChangeConfiguration(ServerRequest))
- {
- return ServerRequest.WriteResponse(
- HttpResponseCode::Unauthorized,
- HttpContentType::kText,
- fmt::format("Removing workspace share {} in workspace {} is not allowed", WorkspaceId, ShareId));
- }
- }
-
- m_WorkspacesStats.WorkspaceShareDeleteCount++;
- bool Deleted = Workspaces::RemoveWorkspaceShare(Log(), Workspace.RootPath, ShareId);
- if (Deleted)
- {
- RefreshState();
- return ServerRequest.WriteResponse(HttpResponseCode::OK);
- }
- return ServerRequest.WriteResponse(HttpResponseCode::NotFound);
- }
- }
-}
-
-} // namespace zen