| 107 | |
| 108 | // Upload parts with the given partNumbers array and complete MPU. |
| 109 | function completeMPU(partNumbers, cb) { |
| 110 | let ETags = []; |
| 111 | |
| 112 | return async.waterfall([ |
| 113 | next => { |
| 114 | const createMpuParams = { |
| 115 | Bucket: bucketName, |
| 116 | Key: objectName, |
| 117 | }; |
| 118 | |
| 119 | s3.send(new CreateMultipartUploadCommand(createMpuParams)).then(data => |
| 120 | next(null, data.UploadId)).catch(next); |
| 121 | }, |
| 122 | (uploadId, next) => |
| 123 | async.eachSeries(partNumbers, (partNumber, callback) => { |
| 124 | const uploadPartParams = { |
| 125 | Bucket: bucketName, |
| 126 | Key: objectName, |
| 127 | PartNumber: partNumber, |
| 128 | UploadId: uploadId, |
| 129 | Body: Buffer.alloc(partSize).fill(partNumber), |
| 130 | }; |
| 131 | return s3.send(new UploadPartCommand(uploadPartParams)).then(data => { |
| 132 | ETags = ETags.concat(data.ETag); |
| 133 | return callback(); |
| 134 | }).catch(callback); |
| 135 | }, err => next(err, uploadId)), |
| 136 | (uploadId, next) => { |
| 137 | const parts = Array.from(Array(partNumbers.length).keys()); |
| 138 | const params = { |
| 139 | Bucket: bucketName, |
| 140 | Key: objectName, |
| 141 | MultipartUpload: { |
| 142 | Parts: parts.map(n => ({ |
| 143 | ETag: ETags[n], |
| 144 | PartNumber: partNumbers[n], |
| 145 | })), |
| 146 | }, |
| 147 | UploadId: uploadId, |
| 148 | }; |
| 149 | return s3.send(new CompleteMultipartUploadCommand(params)).then(() => |
| 150 | next(null, uploadId)).catch(next); |
| 151 | }, |
| 152 | ], (err, uploadId) => { |
| 153 | if (err) { |
| 154 | if (uploadId) { |
| 155 | return s3.send(new AbortMultipartUploadCommand({ |
| 156 | Bucket: bucketName, |
| 157 | Key: objectName, |
| 158 | UploadId: uploadId, |
| 159 | })).then(() => cb(err)).catch(() => cb(err)); |
| 160 | } |
| 161 | return cb(err); |
| 162 | } |
| 163 | return cb(); |
| 164 | }); |
| 165 | } |
| 166 | |