|
5 | 5 | #include <cassert> |
6 | 6 | #include <ranges> |
7 | 7 | #include <regex> |
| 8 | +#include <span> |
8 | 9 |
|
9 | 10 | namespace nix { |
10 | 11 |
|
@@ -46,6 +47,19 @@ class S3BinaryCacheStore : public virtual HttpBinaryCacheStore |
46 | 47 | */ |
47 | 48 | std::string uploadPart(std::string_view key, std::string_view uploadId, uint64_t partNumber, std::string data); |
48 | 49 |
|
| 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 | + |
49 | 63 | /** |
50 | 64 | * Abort a multipart upload |
51 | 65 | * |
@@ -132,6 +146,34 @@ void S3BinaryCacheStore::abortMultipartUpload(std::string_view key, std::string_ |
132 | 146 | getFileTransfer()->enqueueFileTransfer(req).get(); |
133 | 147 | } |
134 | 148 |
|
| 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 | + |
135 | 177 | StringSet S3BinaryCacheStoreConfig::uriSchemes() |
136 | 178 | { |
137 | 179 | return {"s3"}; |
|
0 commit comments