Skip to content

Commit c77317b

Browse files
committed
feat(libstore/s3-binary-cache-store): implement completeMultipartUpload()
`completeMultipartUpload()`: Build XML with part numbers and `ETags`, POST to key with `?uploadId` to finalize the multipart upload
1 parent dd0d006 commit c77317b

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

src/libstore/s3-binary-cache-store.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <cassert>
66
#include <ranges>
77
#include <regex>
8+
#include <span>
89

910
namespace nix {
1011

@@ -46,6 +47,19 @@ class S3BinaryCacheStore : public virtual HttpBinaryCacheStore
4647
*/
4748
std::string uploadPart(std::string_view key, std::string_view uploadId, uint64_t partNumber, std::string data);
4849

50+
struct UploadedPart
51+
{
52+
uint64_t partNumber;
53+
std::string etag;
54+
};
55+
56+
/**
57+
* Completes a multipart upload by combining all uploaded parts.
58+
* @see
59+
* https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html#API_CompleteMultipartUpload_RequestSyntax
60+
*/
61+
void completeMultipartUpload(std::string_view key, std::string_view uploadId, std::span<const UploadedPart> parts);
62+
4963
/**
5064
* Abort a multipart upload
5165
*
@@ -132,6 +146,34 @@ void S3BinaryCacheStore::abortMultipartUpload(std::string_view key, std::string_
132146
getFileTransfer()->enqueueFileTransfer(req).get();
133147
}
134148

149+
void S3BinaryCacheStore::completeMultipartUpload(
150+
std::string_view key, std::string_view uploadId, std::span<const UploadedPart> parts)
151+
{
152+
auto req = makeRequest(key);
153+
req.setupForS3();
154+
155+
auto url = req.uri.parsed();
156+
url.query["uploadId"] = uploadId;
157+
req.uri = VerbatimURL(url);
158+
req.method = HttpMethod::POST;
159+
160+
std::string xml = "<CompleteMultipartUpload>";
161+
for (const auto & part : parts) {
162+
xml += "<Part>";
163+
xml += "<PartNumber>" + std::to_string(part.partNumber) + "</PartNumber>";
164+
xml += "<ETag>" + part.etag + "</ETag>";
165+
xml += "</Part>";
166+
}
167+
xml += "</CompleteMultipartUpload>";
168+
169+
debug("S3 CompleteMultipartUpload XML (%d parts): %s", parts.size(), xml);
170+
171+
req.data = xml;
172+
req.mimeType = "text/xml";
173+
174+
getFileTransfer()->enqueueFileTransfer(req).get();
175+
}
176+
135177
StringSet S3BinaryCacheStoreConfig::uriSchemes()
136178
{
137179
return {"s3"};

0 commit comments

Comments
 (0)