diff options
| author | Stefan Boberg <[email protected]> | 2022-06-10 15:06:10 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2022-06-10 15:06:10 +0200 |
| commit | 8a6c127c3206d59cb73be1caa7d93a1fe4303e6e (patch) | |
| tree | 32d7e025f00c93467cf0b3948c0d9f90cae77ee1 /zenserver/projectstore.cpp | |
| parent | gc: improved message indicating no GC is scheduled (diff) | |
| download | zen-8a6c127c3206d59cb73be1caa7d93a1fe4303e6e.tar.xz zen-8a6c127c3206d59cb73be1caa7d93a1fe4303e6e.zip | |
fixed issue where projects would not be discovered via DiscoverProjects due to use of stem() vs filename()
added /prj/{project}/oplog/{log}/{op} endpoint to allow retrieval of an op entry by LSN. Supports returning CbObject or CbPackage format payloads
Diffstat (limited to 'zenserver/projectstore.cpp')
| -rw-r--r-- | zenserver/projectstore.cpp | 110 |
1 files changed, 100 insertions, 10 deletions
diff --git a/zenserver/projectstore.cpp b/zenserver/projectstore.cpp index d18ae9e1a..7a55911da 100644 --- a/zenserver/projectstore.cpp +++ b/zenserver/projectstore.cpp @@ -450,7 +450,7 @@ ProjectStore::Oplog::IterateOplog(std::function<void(CbObject)>&& Handler) } std::optional<CbObject> -ProjectStore::Oplog::GetOplog(const Oid& Key) +ProjectStore::Oplog::GetOpByKey(const Oid& Key) { RwLock::SharedLockScope _(m_OplogLock); @@ -465,6 +465,19 @@ ProjectStore::Oplog::GetOplog(const Oid& Key) return {}; } +std::optional<CbObject> +ProjectStore::Oplog::GetOpByIndex(int Index) +{ + RwLock::SharedLockScope _(m_OplogLock); + + if (const auto AddressEntryIt = m_OpAddressMap.find(Index); AddressEntryIt != m_OpAddressMap.end()) + { + return m_Storage->GetOp(AddressEntryIt->second); + } + + return {}; +} + bool ProjectStore::Oplog::AddFileMapping(Oid FileId, IoHash Hash, std::string_view ServerPath, std::string_view ClientPath) { @@ -809,7 +822,7 @@ ProjectStore::Project::DiscoverOplogs() for (const std::filesystem::path& DirPath : DirContent.Directories) { - OpenOplog(PathToUtf8(DirPath.stem())); + OpenOplog(PathToUtf8(DirPath.filename())); } } @@ -893,7 +906,7 @@ ProjectStore::DiscoverProjects() for (const std::filesystem::path& DirPath : DirContent.Directories) { - std::string DirName = PathToUtf8(DirPath.stem()); + std::string DirName = PathToUtf8(DirPath.filename()); Project* Project = OpenProject(DirName); if (Project) @@ -917,8 +930,6 @@ ProjectStore::IterateProjects(std::function<void(Project& Prj)>&& Fn) void ProjectStore::Flush() { - // TODO - RwLock::SharedLockScope _(m_ProjectsLock); for (auto& Kv : m_Projects) @@ -1057,6 +1068,8 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) m_Router.AddPattern("chunk", "([[:xdigit:]]{24})"); m_Router.AddPattern("hash", "([[:xdigit:]]{40})"); + // This would ideally just be the response for the root /prj endpoint but this is + // currently not possible for (arbitrary, external) technical reasons m_Router.RegisterRoute( "list", [this](HttpRouterRequest& Req) { @@ -1064,6 +1077,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) CbWriter Response; Response.BeginArray(); + m_ProjectStore->IterateProjects([&Response](ProjectStore::Project& Prj) { Response.BeginObject(); Response << "Id"sv << Prj.Identifier; @@ -1265,7 +1279,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) ProjectStore::Oplog& Log = *FoundLog; - Oid Obj = Oid::FromHexString(ChunkId); + const Oid Obj = Oid::FromHexString(ChunkId); IoBuffer Chunk = Log.FindChunk(Obj); if (!Chunk) @@ -1606,12 +1620,88 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) m_Router.RegisterRoute( "{project}/oplog/{log}/{op}", - [](HttpRouterRequest& Req) { + [this](HttpRouterRequest& Req) { HttpServerRequest& HttpReq = Req.ServerRequest(); - // TODO: look up op and respond with the payload! + const std::string& ProjectId = Req.GetCapture(1); + const std::string& OplogId = Req.GetCapture(2); + const std::string& OpIdString = Req.GetCapture(3); + + ProjectStore::Oplog* FoundLog = m_ProjectStore->OpenProjectOplog(ProjectId, OplogId); + + if (FoundLog == nullptr) + { + return HttpReq.WriteResponse(HttpResponseCode::NotFound); + } + + ProjectStore::Oplog& Oplog = *FoundLog; + + if (const std::optional<int32_t> OpId = zen::ParseInt<uint32_t>(OpIdString)) + { + if (std::optional<CbObject> MaybeOp = Oplog.GetOpByIndex(OpId.value())) + { + CbObject& Op = MaybeOp.value(); + if (Req.ServerRequest().AcceptContentType() == ZenContentType::kCbPackage) + { + CbPackage Package; + Package.SetObject(Op); + + Op.IterateAttachments([&](CbFieldView FieldView) { + const IoHash AttachmentHash = FieldView.AsAttachment(); + IoBuffer Payload = m_CidStore.FindChunkByCid(AttachmentHash); + + // We force this for now as content type is not consistently tracked (will + // be fixed in CidStore refactor) + Payload.SetContentType(ZenContentType::kCompressedBinary); + + if (Payload) + { + switch (Payload.GetContentType()) + { + case ZenContentType::kCbObject: + if (CbObject Object = LoadCompactBinaryObject(Payload)) + { + Package.AddAttachment(CbAttachment(Object)); + } + else + { + // Error - malformed object + + ZEN_ERROR("malformed object returned for {}", AttachmentHash); + } + break; + + case ZenContentType::kCompressedBinary: + if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Payload))) + { + Package.AddAttachment(CbAttachment(Compressed)); + } + else + { + // Error - not compressed! + + ZEN_ERROR("invalid compressed binary returned for {}", AttachmentHash); + } + break; + + default: + Package.AddAttachment(CbAttachment(SharedBuffer(Payload))); + break; + } + } + }); + + return HttpReq.WriteResponse(HttpResponseCode::Accepted, Package); + } + else + { + // Client cannot accept a package, so we only send the core object + return HttpReq.WriteResponse(HttpResponseCode::Accepted, Op); + } + } + } - HttpReq.WriteResponse(HttpResponseCode::Accepted, HttpContentType::kText, u8"yeee"sv); + return HttpReq.WriteResponse(HttpResponseCode::NotFound); }, HttpVerb::kGet); @@ -1718,7 +1808,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects) if (auto OpKey = Params.GetValue("opkey"); !OpKey.empty()) { Oid OpKeyId = OpKeyStringAsOId(OpKey); - std::optional<CbObject> Op = FoundLog->GetOplog(OpKeyId); + std::optional<CbObject> Op = FoundLog->GetOpByKey(OpKeyId); if (Op.has_value()) { |