@aws-amplify/storage 4.4.3 → 4.4.4-in-app-messaging.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -352
- package/dist/aws-amplify-storage.js +6523 -5062
- package/dist/aws-amplify-storage.js.map +1 -1
- package/dist/aws-amplify-storage.min.js +5 -5
- package/dist/aws-amplify-storage.min.js.map +1 -1
- package/lib/Storage.d.ts +3 -1
- package/lib/Storage.js +25 -21
- package/lib/Storage.js.map +1 -1
- package/lib/common/S3ClientUtils.d.ts +33 -0
- package/lib/common/S3ClientUtils.js +179 -0
- package/lib/common/S3ClientUtils.js.map +1 -0
- package/lib/common/StorageConstants.d.ts +4 -0
- package/lib/common/StorageConstants.js +10 -0
- package/lib/common/StorageConstants.js.map +1 -0
- package/lib/common/StorageErrorStrings.d.ts +5 -1
- package/lib/common/StorageErrorStrings.js +5 -0
- package/lib/common/StorageErrorStrings.js.map +1 -1
- package/lib/common/StorageUtils.d.ts +4 -0
- package/lib/common/StorageUtils.js +41 -0
- package/lib/common/StorageUtils.js.map +1 -0
- package/lib/providers/AWSS3Provider.d.ts +9 -6
- package/lib/providers/AWSS3Provider.js +197 -149
- package/lib/providers/AWSS3Provider.js.map +1 -1
- package/lib/providers/AWSS3ProviderManagedUpload.d.ts +3 -10
- package/lib/providers/AWSS3ProviderManagedUpload.js +41 -109
- package/lib/providers/AWSS3ProviderManagedUpload.js.map +1 -1
- package/lib/providers/AWSS3UploadTask.d.ts +107 -0
- package/lib/providers/AWSS3UploadTask.js +610 -0
- package/lib/providers/AWSS3UploadTask.js.map +1 -0
- package/lib/providers/axios-http-handler.d.ts +5 -1
- package/lib/providers/axios-http-handler.js +28 -5
- package/lib/providers/axios-http-handler.js.map +1 -1
- package/lib/types/AWSS3Provider.d.ts +24 -4
- package/lib/types/Provider.d.ts +7 -1
- package/lib/types/Storage.d.ts +8 -8
- package/lib-esm/Storage.d.ts +3 -1
- package/lib-esm/Storage.js +25 -21
- package/lib-esm/Storage.js.map +1 -1
- package/lib-esm/common/S3ClientUtils.d.ts +33 -0
- package/lib-esm/common/S3ClientUtils.js +177 -0
- package/lib-esm/common/S3ClientUtils.js.map +1 -0
- package/lib-esm/common/StorageConstants.d.ts +4 -0
- package/lib-esm/common/StorageConstants.js +8 -0
- package/lib-esm/common/StorageConstants.js.map +1 -0
- package/lib-esm/common/StorageErrorStrings.d.ts +5 -1
- package/lib-esm/common/StorageErrorStrings.js +5 -0
- package/lib-esm/common/StorageErrorStrings.js.map +1 -1
- package/lib-esm/common/StorageUtils.d.ts +4 -0
- package/lib-esm/common/StorageUtils.js +39 -0
- package/lib-esm/common/StorageUtils.js.map +1 -0
- package/lib-esm/providers/AWSS3Provider.d.ts +9 -6
- package/lib-esm/providers/AWSS3Provider.js +192 -144
- package/lib-esm/providers/AWSS3Provider.js.map +1 -1
- package/lib-esm/providers/AWSS3ProviderManagedUpload.d.ts +3 -10
- package/lib-esm/providers/AWSS3ProviderManagedUpload.js +44 -112
- package/lib-esm/providers/AWSS3ProviderManagedUpload.js.map +1 -1
- package/lib-esm/providers/AWSS3UploadTask.d.ts +107 -0
- package/lib-esm/providers/AWSS3UploadTask.js +605 -0
- package/lib-esm/providers/AWSS3UploadTask.js.map +1 -0
- package/lib-esm/providers/axios-http-handler.d.ts +5 -1
- package/lib-esm/providers/axios-http-handler.js +28 -5
- package/lib-esm/providers/axios-http-handler.js.map +1 -1
- package/lib-esm/types/AWSS3Provider.d.ts +24 -4
- package/lib-esm/types/Provider.d.ts +7 -1
- package/lib-esm/types/Storage.d.ts +8 -8
- package/package.json +3 -3
- package/src/Storage.ts +85 -27
- package/src/common/S3ClientUtils.ts +168 -0
- package/src/common/StorageConstants.ts +10 -0
- package/src/common/StorageErrorStrings.ts +5 -0
- package/src/common/StorageUtils.ts +51 -0
- package/src/providers/AWSS3Provider.ts +251 -88
- package/src/providers/AWSS3ProviderManagedUpload.ts +346 -397
- package/src/providers/AWSS3UploadTask.ts +543 -0
- package/src/providers/axios-http-handler.ts +221 -186
- package/src/types/AWSS3Provider.ts +48 -7
- package/src/types/Provider.ts +18 -3
- package/src/types/Storage.ts +9 -9
|
@@ -1,397 +1,346 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
|
|
5
|
-
* the License. A copy of the License is located at
|
|
6
|
-
*
|
|
7
|
-
* http://aws.amazon.com/apache2.0/
|
|
8
|
-
*
|
|
9
|
-
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
10
|
-
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
|
|
11
|
-
* and limitations under the License.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
import * as events from 'events';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
private
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
private
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
this.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
this.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
* @private
|
|
348
|
-
* creates an S3 client with new V3 aws sdk
|
|
349
|
-
*/
|
|
350
|
-
protected async _createNewS3Client(config, emitter?: events.EventEmitter) {
|
|
351
|
-
const credentials = await this._getCredentials();
|
|
352
|
-
const {
|
|
353
|
-
region,
|
|
354
|
-
dangerouslyConnectToHttpEndpointForTesting,
|
|
355
|
-
cancelTokenSource,
|
|
356
|
-
useAccelerateEndpoint
|
|
357
|
-
} = config;
|
|
358
|
-
let localTestingConfig = {};
|
|
359
|
-
|
|
360
|
-
if (dangerouslyConnectToHttpEndpointForTesting) {
|
|
361
|
-
localTestingConfig = {
|
|
362
|
-
endpoint: localTestingStorageEndpoint,
|
|
363
|
-
tls: false,
|
|
364
|
-
bucketEndpoint: false,
|
|
365
|
-
forcePathStyle: true,
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const client = new S3Client({
|
|
370
|
-
region,
|
|
371
|
-
credentials,
|
|
372
|
-
useAccelerateEndpoint,
|
|
373
|
-
...localTestingConfig,
|
|
374
|
-
requestHandler: new AxiosHttpHandler({}, emitter, cancelTokenSource),
|
|
375
|
-
customUserAgent: getAmplifyUserAgent(),
|
|
376
|
-
});
|
|
377
|
-
client.middlewareStack.remove(SET_CONTENT_LENGTH_HEADER);
|
|
378
|
-
return client;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @private
|
|
383
|
-
*/
|
|
384
|
-
_getCredentials() {
|
|
385
|
-
return Credentials.get()
|
|
386
|
-
.then(credentials => {
|
|
387
|
-
if (!credentials) return false;
|
|
388
|
-
const cred = Credentials.shear(credentials);
|
|
389
|
-
logger.debug('set credentials for storage', cred);
|
|
390
|
-
return cred;
|
|
391
|
-
})
|
|
392
|
-
.catch(error => {
|
|
393
|
-
logger.warn('ensure credentials error', error);
|
|
394
|
-
return false;
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
|
|
5
|
+
* the License. A copy of the License is located at
|
|
6
|
+
*
|
|
7
|
+
* http://aws.amazon.com/apache2.0/
|
|
8
|
+
*
|
|
9
|
+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
10
|
+
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
|
|
11
|
+
* and limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { ConsoleLogger as Logger } from '@aws-amplify/core';
|
|
15
|
+
import {
|
|
16
|
+
PutObjectCommand,
|
|
17
|
+
PutObjectRequest,
|
|
18
|
+
CreateMultipartUploadCommand,
|
|
19
|
+
UploadPartCommand,
|
|
20
|
+
CompleteMultipartUploadCommand,
|
|
21
|
+
CompleteMultipartUploadCommandInput,
|
|
22
|
+
ListPartsCommand,
|
|
23
|
+
AbortMultipartUploadCommand,
|
|
24
|
+
CompletedPart,
|
|
25
|
+
S3Client,
|
|
26
|
+
} from '@aws-sdk/client-s3';
|
|
27
|
+
import {
|
|
28
|
+
SEND_UPLOAD_PROGRESS_EVENT,
|
|
29
|
+
SEND_DOWNLOAD_PROGRESS_EVENT,
|
|
30
|
+
AxiosHttpHandlerOptions,
|
|
31
|
+
} from './axios-http-handler';
|
|
32
|
+
import * as events from 'events';
|
|
33
|
+
import {
|
|
34
|
+
createPrefixMiddleware,
|
|
35
|
+
prefixMiddlewareOptions,
|
|
36
|
+
autoAdjustClockskewMiddleware,
|
|
37
|
+
autoAdjustClockskewMiddlewareOptions,
|
|
38
|
+
createS3Client,
|
|
39
|
+
} from '../common/S3ClientUtils';
|
|
40
|
+
|
|
41
|
+
const logger = new Logger('AWSS3ProviderManagedUpload');
|
|
42
|
+
|
|
43
|
+
export declare interface Part {
|
|
44
|
+
bodyPart: any;
|
|
45
|
+
partNumber: number;
|
|
46
|
+
emitter: events.EventEmitter;
|
|
47
|
+
etag?: string;
|
|
48
|
+
_lastUploadedBytes: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class AWSS3ProviderManagedUpload {
|
|
52
|
+
// Defaults
|
|
53
|
+
protected minPartSize = 5 * 1024 * 1024; // in MB
|
|
54
|
+
private queueSize = 4;
|
|
55
|
+
|
|
56
|
+
// Data for current upload
|
|
57
|
+
private body = null;
|
|
58
|
+
private params: PutObjectRequest = null;
|
|
59
|
+
private opts = null;
|
|
60
|
+
private completedParts: CompletedPart[] = [];
|
|
61
|
+
private cancel = false;
|
|
62
|
+
private s3client: S3Client;
|
|
63
|
+
|
|
64
|
+
// Progress reporting
|
|
65
|
+
private bytesUploaded = 0;
|
|
66
|
+
private totalBytesToUpload = 0;
|
|
67
|
+
private emitter: events.EventEmitter = null;
|
|
68
|
+
|
|
69
|
+
constructor(params: PutObjectRequest, opts, emitter: events.EventEmitter) {
|
|
70
|
+
this.params = params;
|
|
71
|
+
this.opts = opts;
|
|
72
|
+
this.emitter = emitter;
|
|
73
|
+
this.s3client = this._createNewS3Client(opts, emitter);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public async upload() {
|
|
77
|
+
this.body = await this.validateAndSanitizeBody(this.params.Body);
|
|
78
|
+
this.totalBytesToUpload = this.byteLength(this.body);
|
|
79
|
+
if (this.totalBytesToUpload <= this.minPartSize) {
|
|
80
|
+
// Multipart upload is not required. Upload the sanitized body as is
|
|
81
|
+
this.params.Body = this.body;
|
|
82
|
+
const putObjectCommand = new PutObjectCommand(this.params);
|
|
83
|
+
return this.s3client.send(putObjectCommand);
|
|
84
|
+
} else {
|
|
85
|
+
// Step 1: Initiate the multi part upload
|
|
86
|
+
const uploadId = await this.createMultiPartUpload();
|
|
87
|
+
|
|
88
|
+
// Step 2: Upload chunks in parallel as requested
|
|
89
|
+
const numberOfPartsToUpload = Math.ceil(
|
|
90
|
+
this.totalBytesToUpload / this.minPartSize
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const parts: Part[] = this.createParts();
|
|
94
|
+
for (
|
|
95
|
+
let start = 0;
|
|
96
|
+
start < numberOfPartsToUpload;
|
|
97
|
+
start += this.queueSize
|
|
98
|
+
) {
|
|
99
|
+
/** This first block will try to cancel the upload if the cancel
|
|
100
|
+
* request came before any parts uploads have started.
|
|
101
|
+
**/
|
|
102
|
+
await this.checkIfUploadCancelled(uploadId);
|
|
103
|
+
|
|
104
|
+
// Upload as many as `queueSize` parts simultaneously
|
|
105
|
+
await this.uploadParts(
|
|
106
|
+
uploadId,
|
|
107
|
+
parts.slice(start, start + this.queueSize)
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
/** Call cleanup a second time in case there were part upload requests
|
|
111
|
+
* in flight. This is to ensure that all parts are cleaned up.
|
|
112
|
+
*/
|
|
113
|
+
await this.checkIfUploadCancelled(uploadId);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
parts.map(part => {
|
|
117
|
+
this.removeEventListener(part);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Step 3: Finalize the upload such that S3 can recreate the file
|
|
121
|
+
return await this.finishMultiPartUpload(uploadId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private createParts(): Part[] {
|
|
126
|
+
const parts: Part[] = [];
|
|
127
|
+
for (let bodyStart = 0; bodyStart < this.totalBytesToUpload; ) {
|
|
128
|
+
const bodyEnd = Math.min(
|
|
129
|
+
bodyStart + this.minPartSize,
|
|
130
|
+
this.totalBytesToUpload
|
|
131
|
+
);
|
|
132
|
+
parts.push({
|
|
133
|
+
bodyPart: this.body.slice(bodyStart, bodyEnd),
|
|
134
|
+
partNumber: parts.length + 1,
|
|
135
|
+
emitter: new events.EventEmitter(),
|
|
136
|
+
_lastUploadedBytes: 0,
|
|
137
|
+
});
|
|
138
|
+
bodyStart += this.minPartSize;
|
|
139
|
+
}
|
|
140
|
+
return parts;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private async createMultiPartUpload() {
|
|
144
|
+
const createMultiPartUploadCommand = new CreateMultipartUploadCommand(
|
|
145
|
+
this.params
|
|
146
|
+
);
|
|
147
|
+
const response = await this.s3client.send(createMultiPartUploadCommand);
|
|
148
|
+
logger.debug(response.UploadId);
|
|
149
|
+
return response.UploadId;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @private Not to be extended outside of tests
|
|
154
|
+
* @VisibleFotTesting
|
|
155
|
+
*/
|
|
156
|
+
protected async uploadParts(uploadId: string, parts: Part[]) {
|
|
157
|
+
try {
|
|
158
|
+
const allResults = await Promise.all(
|
|
159
|
+
parts.map(async part => {
|
|
160
|
+
this.setupEventListener(part);
|
|
161
|
+
const options: AxiosHttpHandlerOptions = { emitter: part.emitter };
|
|
162
|
+
const {
|
|
163
|
+
Key,
|
|
164
|
+
Bucket,
|
|
165
|
+
SSECustomerAlgorithm,
|
|
166
|
+
SSECustomerKey,
|
|
167
|
+
SSECustomerKeyMD5,
|
|
168
|
+
} = this.params;
|
|
169
|
+
const res = await this.s3client.send(
|
|
170
|
+
new UploadPartCommand({
|
|
171
|
+
PartNumber: part.partNumber,
|
|
172
|
+
Body: part.bodyPart,
|
|
173
|
+
UploadId: uploadId,
|
|
174
|
+
Key,
|
|
175
|
+
Bucket,
|
|
176
|
+
...(SSECustomerAlgorithm && { SSECustomerAlgorithm }),
|
|
177
|
+
...(SSECustomerKey && { SSECustomerKey }),
|
|
178
|
+
...(SSECustomerKeyMD5 && { SSECustomerKeyMD5 }),
|
|
179
|
+
}),
|
|
180
|
+
options
|
|
181
|
+
);
|
|
182
|
+
return res;
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
// The order of resolved promises is the same as input promise order.
|
|
186
|
+
for (let i = 0; i < allResults.length; i++) {
|
|
187
|
+
this.completedParts.push({
|
|
188
|
+
PartNumber: parts[i].partNumber,
|
|
189
|
+
ETag: allResults[i].ETag,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
} catch (error) {
|
|
193
|
+
logger.error(
|
|
194
|
+
'error happened while uploading a part. Cancelling the multipart upload',
|
|
195
|
+
error
|
|
196
|
+
);
|
|
197
|
+
this.cancelUpload();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private async finishMultiPartUpload(uploadId: string) {
|
|
203
|
+
const input: CompleteMultipartUploadCommandInput = {
|
|
204
|
+
Bucket: this.params.Bucket,
|
|
205
|
+
Key: this.params.Key,
|
|
206
|
+
UploadId: uploadId,
|
|
207
|
+
MultipartUpload: { Parts: this.completedParts },
|
|
208
|
+
};
|
|
209
|
+
const completeUploadCommand = new CompleteMultipartUploadCommand(input);
|
|
210
|
+
try {
|
|
211
|
+
const data = await this.s3client.send(completeUploadCommand);
|
|
212
|
+
return data.Key;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
logger.error(
|
|
215
|
+
'error happened while finishing the upload. Cancelling the multipart upload',
|
|
216
|
+
error
|
|
217
|
+
);
|
|
218
|
+
this.cancelUpload();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private async checkIfUploadCancelled(uploadId: string) {
|
|
224
|
+
if (this.cancel) {
|
|
225
|
+
let errorMessage = 'Upload was cancelled.';
|
|
226
|
+
try {
|
|
227
|
+
await this.cleanup(uploadId);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
errorMessage += ` ${error.message}`;
|
|
230
|
+
}
|
|
231
|
+
throw new Error(errorMessage);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public cancelUpload() {
|
|
236
|
+
this.cancel = true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private async cleanup(uploadId: string) {
|
|
240
|
+
// Reset this's state
|
|
241
|
+
this.body = null;
|
|
242
|
+
this.completedParts = [];
|
|
243
|
+
this.bytesUploaded = 0;
|
|
244
|
+
this.totalBytesToUpload = 0;
|
|
245
|
+
|
|
246
|
+
const input = {
|
|
247
|
+
Bucket: this.params.Bucket,
|
|
248
|
+
Key: this.params.Key,
|
|
249
|
+
UploadId: uploadId,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
await this.s3client.send(new AbortMultipartUploadCommand(input));
|
|
253
|
+
|
|
254
|
+
// verify that all parts are removed.
|
|
255
|
+
const data = await this.s3client.send(new ListPartsCommand(input));
|
|
256
|
+
|
|
257
|
+
if (data && data.Parts && data.Parts.length > 0) {
|
|
258
|
+
throw new Error('Multi Part upload clean up failed');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private removeEventListener(part: Part) {
|
|
263
|
+
part.emitter.removeAllListeners(SEND_UPLOAD_PROGRESS_EVENT);
|
|
264
|
+
part.emitter.removeAllListeners(SEND_DOWNLOAD_PROGRESS_EVENT);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private setupEventListener(part: Part) {
|
|
268
|
+
part.emitter.on(SEND_UPLOAD_PROGRESS_EVENT, progress => {
|
|
269
|
+
this.progressChanged(
|
|
270
|
+
part.partNumber,
|
|
271
|
+
progress.loaded - part._lastUploadedBytes
|
|
272
|
+
);
|
|
273
|
+
part._lastUploadedBytes = progress.loaded;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private progressChanged(partNumber: number, incrementalUpdate: number) {
|
|
278
|
+
this.bytesUploaded += incrementalUpdate;
|
|
279
|
+
this.emitter.emit(SEND_UPLOAD_PROGRESS_EVENT, {
|
|
280
|
+
loaded: this.bytesUploaded,
|
|
281
|
+
total: this.totalBytesToUpload,
|
|
282
|
+
part: partNumber,
|
|
283
|
+
key: this.params.Key,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private byteLength(input: any) {
|
|
288
|
+
if (input === null || input === undefined) return 0;
|
|
289
|
+
if (typeof input.byteLength === 'number') {
|
|
290
|
+
return input.byteLength;
|
|
291
|
+
} else if (typeof input.length === 'number') {
|
|
292
|
+
return input.length;
|
|
293
|
+
} else if (typeof input.size === 'number') {
|
|
294
|
+
return input.size;
|
|
295
|
+
} else if (typeof input.path === 'string') {
|
|
296
|
+
/* NodeJs Support
|
|
297
|
+
return require('fs').lstatSync(input.path).size;
|
|
298
|
+
*/
|
|
299
|
+
} else {
|
|
300
|
+
throw new Error('Cannot determine length of ' + input);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private async validateAndSanitizeBody(body: any): Promise<any> {
|
|
305
|
+
if (this.isGenericObject(body)) {
|
|
306
|
+
// Any javascript object
|
|
307
|
+
return JSON.stringify(body);
|
|
308
|
+
} else {
|
|
309
|
+
// Files, arrayBuffer etc
|
|
310
|
+
return body;
|
|
311
|
+
}
|
|
312
|
+
/* TODO: streams and files for nodejs
|
|
313
|
+
if (
|
|
314
|
+
typeof body.path === 'string' &&
|
|
315
|
+
require('fs').lstatSync(body.path).size > 0
|
|
316
|
+
) {
|
|
317
|
+
return body;
|
|
318
|
+
} */
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
private isGenericObject(body: any): body is Object {
|
|
322
|
+
if (body !== null && typeof body === 'object') {
|
|
323
|
+
try {
|
|
324
|
+
return !(this.byteLength(body) >= 0);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
// If we cannot determine the length of the body, consider it
|
|
327
|
+
// as a generic object and upload a stringified version of it
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
protected _createNewS3Client(config, emitter?: events.EventEmitter) {
|
|
335
|
+
const s3client = createS3Client(config, emitter);
|
|
336
|
+
s3client.middlewareStack.add(
|
|
337
|
+
createPrefixMiddleware(this.opts, this.params.Key),
|
|
338
|
+
prefixMiddlewareOptions
|
|
339
|
+
);
|
|
340
|
+
s3client.middlewareStack.add(
|
|
341
|
+
autoAdjustClockskewMiddleware(s3client.config),
|
|
342
|
+
autoAdjustClockskewMiddlewareOptions
|
|
343
|
+
);
|
|
344
|
+
return s3client;
|
|
345
|
+
}
|
|
346
|
+
}
|