dpu-cloud-sdk 1.0.0

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.
Files changed (51) hide show
  1. package/.env.development +1 -0
  2. package/.env.production +1 -0
  3. package/dist/DPUClient.d.ts +83 -0
  4. package/dist/DPUClient.js +1043 -0
  5. package/dist/ServiceIntegration.d.ts +20 -0
  6. package/dist/ServiceIntegration.js +506 -0
  7. package/dist/api/auth.d.ts +3 -0
  8. package/dist/api/auth.js +10 -0
  9. package/dist/api/compress.d.ts +4 -0
  10. package/dist/api/compress.js +16 -0
  11. package/dist/api/translate.d.ts +8 -0
  12. package/dist/api/translate.js +38 -0
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.js +4 -0
  15. package/dist/models/RequestModel.d.ts +33 -0
  16. package/dist/models/RequestModel.js +2 -0
  17. package/dist/models/ResponseModel.d.ts +99 -0
  18. package/dist/models/ResponseModel.js +1 -0
  19. package/dist/utils/Config.d.ts +32 -0
  20. package/dist/utils/Config.js +44 -0
  21. package/dist/utils/Constants.d.ts +48 -0
  22. package/dist/utils/Constants.js +55 -0
  23. package/dist/utils/Enum.d.ts +27 -0
  24. package/dist/utils/Enum.js +30 -0
  25. package/dist/utils/Helper.d.ts +4 -0
  26. package/dist/utils/Helper.js +47 -0
  27. package/dist/workerDownloadSingleFile.d.ts +1 -0
  28. package/dist/workerDownloadSingleFile.js +35 -0
  29. package/dist/workerUploadChildFile.d.ts +1 -0
  30. package/dist/workerUploadChildFile.js +82 -0
  31. package/dist/workerUploadSingleFile.d.ts +1 -0
  32. package/dist/workerUploadSingleFile.js +93 -0
  33. package/dpubim-service-1.1.28.tgz +0 -0
  34. package/package.json +33 -0
  35. package/src/DPUClient.ts +1505 -0
  36. package/src/ServiceIntegration.ts +710 -0
  37. package/src/api/auth.ts +18 -0
  38. package/src/api/compress.ts +36 -0
  39. package/src/api/translate.ts +94 -0
  40. package/src/index.ts +4 -0
  41. package/src/models/RequestModel.ts +44 -0
  42. package/src/models/ResponseModel.ts +110 -0
  43. package/src/utils/Config.ts +59 -0
  44. package/src/utils/Constants.ts +61 -0
  45. package/src/utils/Enum.ts +29 -0
  46. package/src/utils/Helper.ts +57 -0
  47. package/src/workerDownloadSingleFile.ts +34 -0
  48. package/src/workerUploadChildFile.ts +85 -0
  49. package/src/workerUploadSingleFile.ts +123 -0
  50. package/tsconfig.json +108 -0
  51. package/webpack.config.js +43 -0
@@ -0,0 +1,710 @@
1
+ import { FileDownloadInfo } from "./models/RequestModel";
2
+ import {
3
+ BaseReponseModel,
4
+ InitUploadResponse,
5
+ PresignURLResponse,
6
+ ObjectDetail,
7
+ CompleteMultipartUploadResponse,
8
+ MultiPresignURLResponse,
9
+ } from "./models/ResponseModel";
10
+ import { ApiStatus, ConfigFileRules, Path } from "./utils/Constants";
11
+ import { validString } from "./utils/Helper";
12
+
13
+ export class ServiceIntegration {
14
+ constructor() {}
15
+
16
+ public async getUrlToDownload(
17
+ bucketName: string,
18
+ fileName: string,
19
+ accessToken?: string
20
+ ) {
21
+ try {
22
+ const url = `${Path.BaseURL}${Path.GetUrlDownload}`;
23
+ const headers: any = {
24
+ Authorization: `Bearer ${accessToken}`,
25
+ "Content-Type": "application/json",
26
+ "ngrok-skip-browser-warning": true,
27
+ };
28
+
29
+ let queryParams: any;
30
+ if (validString(bucketName)) {
31
+ queryParams = { ...queryParams, bucketName: bucketName };
32
+ }
33
+ if (validString(fileName)) {
34
+ queryParams = { ...queryParams, fileName: fileName };
35
+ }
36
+
37
+ const response = await fetch(
38
+ `${url}?${new URLSearchParams(queryParams)}`,
39
+ {
40
+ method: "GET",
41
+ headers: headers,
42
+ }
43
+ );
44
+ if (response.ok) {
45
+ const json: BaseReponseModel<string> =
46
+ (await response.json()) as BaseReponseModel<string>;
47
+ if (json.statusCode === ApiStatus.Success) {
48
+ return json.data;
49
+ } else {
50
+ console.error(
51
+ `Fail to generate url download with message error: ${json.message}`
52
+ );
53
+ }
54
+ } else {
55
+ console.error(
56
+ `Fail to generate url download with status ${response.statusText} and error: ${response.statusText}`
57
+ );
58
+ }
59
+
60
+ return null;
61
+ } catch (error) {
62
+ console.error(`Error when generate url download: ${error}`);
63
+ }
64
+ }
65
+
66
+ public async fetchChunkFile(url: string, start: number, end: number) {
67
+ try {
68
+ const response = await fetch(url, {
69
+ method: "GET",
70
+ headers: {
71
+ Range: `bytes=${start}-${end}`,
72
+ },
73
+ });
74
+ if (!response.ok) {
75
+ const error = `Fail to fetch chunk file with status ${
76
+ response.statusText
77
+ } and error: ${await response.text()}`;
78
+ throw new Error(error);
79
+ }
80
+
81
+ return await response.arrayBuffer();
82
+ } catch (error) {
83
+ console.error(`Error when download file: ${error}`);
84
+ throw error;
85
+ }
86
+ }
87
+
88
+ //#region Upload small file
89
+ public async uploadSmallFile(
90
+ bucketName: string,
91
+ fileName: string,
92
+ buffer: Buffer,
93
+ // file: File,
94
+ accessToken: string,
95
+ cancellationToken: AbortController,
96
+ onProgress?: (percentCompleted: number) => void,
97
+ reGetAccessToken?: () => string,
98
+ isGetInfo?: boolean,
99
+ preSignUrl?: PresignURLResponse
100
+ ) {
101
+ if(!preSignUrl) {
102
+ const presignUrlResponse = await this.generatePresignedUrl(
103
+ bucketName,
104
+ fileName,
105
+ accessToken,
106
+ cancellationToken
107
+ );
108
+ if (!presignUrlResponse) {
109
+ return new Promise((resolve, reject) => {
110
+ reject(`Fail to generate presigned url for file ${fileName}`);
111
+ });
112
+ }
113
+ preSignUrl = presignUrlResponse;
114
+ }
115
+
116
+ var responseUploadChild = await this.uploadChildFile(
117
+ preSignUrl,
118
+ buffer,
119
+ cancellationToken
120
+ );
121
+
122
+ if (!responseUploadChild) {
123
+ return new Promise((resolve, reject) => {
124
+ reject(`Fail to upload file ${fileName}`);
125
+ });
126
+ }
127
+
128
+ if (isGetInfo === true) {
129
+ const objectDetail: ObjectDetail | null = await this.getObjectDetail(
130
+ bucketName,
131
+ fileName,
132
+ accessToken
133
+ );
134
+ if (!objectDetail) {
135
+ return new Promise((resolve, reject) => {
136
+ reject(`Fail to get object detail for file ${fileName}`);
137
+ });
138
+ }
139
+ const fileModel = {
140
+ bucketName: bucketName,
141
+ fileName: fileName,
142
+ contentLength: buffer.length,
143
+ versionFile: objectDetail.versionId,
144
+ dateVersionFile: objectDetail.lastModified,
145
+ };
146
+
147
+ return new Promise((resolve, reject) => {
148
+ resolve(fileModel);
149
+ });
150
+ }
151
+
152
+ return new Promise((resolve, reject) => {
153
+ resolve({
154
+ bucketName: bucketName,
155
+ fileName: fileName,
156
+ contentLength: buffer.length,
157
+ versionFile: null,
158
+ dateVersionFile: null,
159
+ });
160
+ });
161
+ }
162
+
163
+ private async generatePresignedUrl(
164
+ bucketName: string,
165
+ fileName: string,
166
+ accessToken?: string,
167
+ cancellationToken?: AbortController
168
+ ) {
169
+ try {
170
+ const url = `${Path.BaseURL}${Path.GeneratePresignedUrl}`;
171
+ const headers: any = {
172
+ Authorization: `Bearer ${accessToken}`,
173
+ "Content-Type": "application/json",
174
+ "ngrok-skip-browser-warning": true,
175
+ };
176
+
177
+ let queryParams: any = {
178
+ setPermission: false,
179
+ };
180
+ if (validString(bucketName)) {
181
+ queryParams = { ...queryParams, bucketName: bucketName };
182
+ }
183
+ if (validString(fileName)) {
184
+ queryParams = { ...queryParams, objectName: fileName };
185
+ }
186
+
187
+ const response = await fetch(
188
+ `${url}?${new URLSearchParams(queryParams)}`,
189
+ {
190
+ method: "GET",
191
+ headers: headers,
192
+ signal: cancellationToken?.signal
193
+ }
194
+ );
195
+ if (response.ok) {
196
+ const json: BaseReponseModel<PresignURLResponse> =
197
+ (await response.json()) as BaseReponseModel<PresignURLResponse>;
198
+ if (json.statusCode === ApiStatus.Success) {
199
+ return json.data;
200
+ } else {
201
+ console.error(
202
+ `Fail to generate presigned urls with message error: ${json.message}`
203
+ );
204
+ }
205
+ } else {
206
+ console.error(
207
+ `Fail to generate presigned urls with status ${response.statusText} and error: ${response.statusText}`
208
+ );
209
+ }
210
+
211
+ return null;
212
+ } catch (error) {
213
+ console.error(`Error when generate presigned urls: ${error}`);
214
+ }
215
+ }
216
+
217
+ private async uploadChildFile(
218
+ presignUrlResponse: PresignURLResponse,
219
+ buffer: ArrayBuffer,
220
+ cancellationToken?: AbortController
221
+ ) {
222
+ try {
223
+ const response = await fetch(presignUrlResponse.url, {
224
+ method: "PUT",
225
+ headers: presignUrlResponse.headers,
226
+ body: buffer,
227
+ signal: cancellationToken?.signal
228
+ });
229
+
230
+ if (response.status === ApiStatus.Success) {
231
+ var eTag: string | null = response.headers.get("ETag");
232
+ if (eTag) return eTag.replace(/^"|"$/g, "");
233
+ } else {
234
+ console.error(
235
+ `Fail to upload child file with status ${response.statusText} and error: ${response.statusText}`
236
+ );
237
+ }
238
+
239
+ return null;
240
+ } catch (error) {
241
+ console.error(`Error when upload child file: ${error}`);
242
+ }
243
+ }
244
+ //#endregion
245
+
246
+ //#region Upload large file
247
+ public async uploadLargeFile(
248
+ bucketName: string,
249
+ fileName: string,
250
+ buffer: Buffer,
251
+ accessToken: string,
252
+ cancellationToken: AbortController,
253
+ onProgress?: (percentCompleted: number) => void,
254
+ reGetAccessToken?: () => string,
255
+ initUpload?: InitUploadResponse,
256
+ isGetInfo?: boolean
257
+ ) {
258
+ await this.validateFileSize(fileName, buffer.length);
259
+ // init multi upload
260
+ if (!initUpload) {
261
+ initUpload = await this.initMultiPartUpload(
262
+ bucketName,
263
+ fileName,
264
+ accessToken,
265
+ false,
266
+ cancellationToken
267
+ );
268
+ }
269
+ if (!initUpload) {
270
+ return new Promise((resolve, reject) => {
271
+ reject(`Fail to initiate multipart upload for file ${fileName}`);
272
+ });
273
+ }
274
+ var numberOfChunks: number = this.calculateNumberOfChunks(
275
+ buffer.length
276
+ );
277
+ const urls = await this.generatePresignedUrls(
278
+ bucketName,
279
+ fileName,
280
+ initUpload,
281
+ numberOfChunks,
282
+ accessToken,
283
+ cancellationToken
284
+ );
285
+ if (!urls) {
286
+ return new Promise((resolve, reject) => {
287
+ reject(`Fail to generate presigned urls for file ${fileName}`);
288
+ });
289
+ }
290
+
291
+ var chunksUploaded: number = 0;
292
+ var start: number = 0;
293
+ const eTags: any = {};
294
+ while (chunksUploaded < numberOfChunks) {
295
+ this.throwIfCancellationRequested(cancellationToken, fileName);
296
+ var end: number = Math.min(
297
+ start + ConfigFileRules.ChunkSize,
298
+ buffer.length
299
+ );
300
+ // var fileChunk: ArrayBuffer = await this.readFileBytes(file, start, end);
301
+ const sliced = buffer.subarray(start, end); // lấy phần con của buffer
302
+ const fileChunk = sliced.buffer.slice(sliced.byteOffset, sliced.byteOffset + sliced.byteLength);
303
+ this.throwIfCancellationRequested(cancellationToken, fileName);
304
+ var url: string = urls[chunksUploaded];
305
+ var responseUploadChild = await this.uploadChildFile(
306
+ { url: url, headers: initUpload.headers },
307
+ fileChunk
308
+ );
309
+ if (!responseUploadChild) {
310
+ return new Promise((resolve, reject) => {
311
+ reject(`Fail to upload chunk ${chunksUploaded} of file ${fileName}`);
312
+ });
313
+ }
314
+ Object.defineProperty(eTags, chunksUploaded + 1, {
315
+ value: responseUploadChild,
316
+ enumerable: true,
317
+ });
318
+ chunksUploaded++;
319
+ start = end;
320
+ var percentCompleted: number = (chunksUploaded / numberOfChunks) * 100;
321
+ onProgress?.(percentCompleted);
322
+ // console.log(`${requestId} Number of chunks uploaded : ${chunksUploaded}`);
323
+ }
324
+ var completeResponse = await this.completeMultipartUpload(
325
+ bucketName,
326
+ fileName,
327
+ initUpload.uploadId,
328
+ eTags,
329
+ accessToken,
330
+ cancellationToken
331
+ );
332
+ onProgress?.(100);
333
+ if (!completeResponse) {
334
+ return new Promise((resolve, reject) => {
335
+ reject(`Fail to complete multipart upload for file ${fileName}`);
336
+ });
337
+ }
338
+ if (isGetInfo === false) {
339
+ return new Promise((resolve, reject) => {
340
+ resolve(fileName);
341
+ });
342
+ } else {
343
+ const objectDetail: ObjectDetail | null = await this.getObjectDetail(
344
+ bucketName,
345
+ fileName,
346
+ accessToken
347
+ );
348
+ if (!objectDetail) {
349
+ return new Promise((resolve, reject) => {
350
+ reject(`Fail to get object detail for file ${fileName}`);
351
+ });
352
+ }
353
+ const fileModel = {
354
+ bucketName: bucketName,
355
+ fileName: fileName,
356
+ contentLength: buffer.length,
357
+ versionFile: objectDetail.versionId,
358
+ dateVersionFile: objectDetail.lastModified,
359
+ };
360
+
361
+ return new Promise((resolve, reject) => {
362
+ resolve(fileModel);
363
+ });
364
+ }
365
+ }
366
+
367
+ public async validateFileSize(fileName: string, fileSize: number) {
368
+ var sizeAllowed = await this.isFileSizeAllowed(fileSize);
369
+ if (!sizeAllowed) {
370
+ console.error(
371
+ `File size of ${fileName} too big to upload. Currently max file size allowed is ${
372
+ Number(ConfigFileRules.MaxChunkCountAllowed) *
373
+ Number(ConfigFileRules.ChunkSize)
374
+ } bytes`
375
+ );
376
+ // throw new OssApiError(`${requestId} File size too big to upload. Currently max file size allowed is ${Number(ConfigFileRules.MaxChunkCountAllowed) * Number(Constants.ChunkSize)} bytes`);
377
+ }
378
+ }
379
+
380
+ private async isFileSizeAllowed(fileSize: number): Promise<boolean> {
381
+ const numberOfChunks: number = this.calculateNumberOfChunks(fileSize);
382
+ if (numberOfChunks > ConfigFileRules.MaxChunkCountAllowed) {
383
+ return false;
384
+ }
385
+ return true;
386
+ }
387
+
388
+ public calculateNumberOfChunks(fileSize: number): number {
389
+ if (fileSize == 0) {
390
+ return 1;
391
+ }
392
+ var numberOfChunks: number = Math.trunc(
393
+ fileSize / ConfigFileRules.ChunkSize
394
+ );
395
+
396
+ if (fileSize % ConfigFileRules.ChunkSize != 0) {
397
+ numberOfChunks++;
398
+ }
399
+ return numberOfChunks;
400
+ }
401
+
402
+ public async getObjectDetail(
403
+ bucketName: string,
404
+ fileName: string,
405
+ accessToken?: string
406
+ ) {
407
+ try {
408
+ const url = `${Path.BaseURL}${Path.GetObjectDetail}`;
409
+ const headers: any = {
410
+ Authorization: `Bearer ${accessToken}`,
411
+ "Content-Type": "application/json",
412
+ "ngrok-skip-browser-warning": true,
413
+ };
414
+ let queryParams: any;
415
+ if (validString(bucketName)) {
416
+ queryParams = { ...queryParams, bucketName: bucketName };
417
+ }
418
+ if (validString(fileName)) {
419
+ queryParams = { ...queryParams, objectName: fileName };
420
+ }
421
+ const response = await fetch(
422
+ `${url}?${new URLSearchParams(queryParams)}`,
423
+ {
424
+ method: "GET",
425
+ headers: headers,
426
+ }
427
+ );
428
+ if (response.ok) {
429
+ const json: BaseReponseModel<ObjectDetail> =
430
+ (await response.json()) as BaseReponseModel<ObjectDetail>;
431
+ if (json.statusCode === ApiStatus.Success) {
432
+ return json.data;
433
+ } else {
434
+ console.error(
435
+ `Fail to generate presigned urls with message error: ${json.message}`
436
+ );
437
+ }
438
+ } else {
439
+ console.error(
440
+ `Fail to generate presigned urls with status ${response.statusText} and error: ${response.statusText}`
441
+ );
442
+ }
443
+ } catch (error) {
444
+ console.error(`Error when get file info: ${error}`);
445
+ }
446
+
447
+ return null;
448
+ }
449
+
450
+ public async initMultiPartUpload(
451
+ bucketName: string,
452
+ fileName: string,
453
+ accessToken?: string,
454
+ autoCreateBucket?: boolean | false,
455
+ cancellationToken?: AbortController
456
+ ) {
457
+ try {
458
+ const url = `${Path.BaseURL}${Path.InitiateMultipartUpload}`;
459
+ const headers: any = {
460
+ Authorization: `Bearer ${accessToken}`,
461
+ "Content-Type": "application/json",
462
+ "ngrok-skip-browser-warning": true,
463
+ };
464
+
465
+ let queryParams: any;
466
+ if (validString(bucketName)) {
467
+ queryParams = { ...queryParams, bucketName: bucketName };
468
+ }
469
+ if (validString(fileName)) {
470
+ queryParams = { ...queryParams, objectName: fileName };
471
+ }
472
+ if (autoCreateBucket === true) {
473
+ queryParams = { ...queryParams, autoCreateBucket: autoCreateBucket };
474
+ }
475
+
476
+ queryParams = { ...queryParams, setPermission: false };
477
+
478
+ const response = await fetch(
479
+ `${url}?${new URLSearchParams(queryParams)}`,
480
+ {
481
+ method: "GET",
482
+ headers: headers,
483
+ }
484
+ );
485
+ if (response.ok) {
486
+ const json: BaseReponseModel<InitUploadResponse> =
487
+ (await response.json()) as BaseReponseModel<InitUploadResponse>;
488
+ if (json.statusCode === ApiStatus.Success) {
489
+ return json.data;
490
+ } else {
491
+ console.error(
492
+ `Fail to initiate multipart upload with message error: ${json.message}`
493
+ );
494
+ }
495
+ } else {
496
+ console.error(
497
+ `Fail to initiate multipart upload with status ${response.statusText} and error: ${response.statusText}`
498
+ );
499
+ }
500
+ } catch (error) {
501
+ console.error(`Error when initiate multipart upload: ${error}`);
502
+ }
503
+
504
+ return undefined;
505
+ }
506
+
507
+ public async generatePresignedUrls(
508
+ bucketName: string,
509
+ fileName: string,
510
+ initUpload: InitUploadResponse,
511
+ totalPart: number,
512
+ accessToken: string,
513
+ cancellationToken?: AbortController
514
+ ) {
515
+ try {
516
+ const url = `${Path.BaseURL}${Path.GeneratePresignedUrls}`;
517
+ const headers = initUpload.headers;
518
+
519
+ let queryParams: any;
520
+ if (validString(bucketName)) {
521
+ queryParams = { ...queryParams, bucketName: bucketName };
522
+ }
523
+ if (validString(fileName)) {
524
+ queryParams = { ...queryParams, objectName: fileName };
525
+ }
526
+ if (validString(initUpload.uploadId)) {
527
+ queryParams = { ...queryParams, uploadId: initUpload.uploadId };
528
+ }
529
+ if (totalPart > 0) {
530
+ queryParams = { ...queryParams, totalPart: totalPart };
531
+ }
532
+
533
+ const newHeaders: any = {
534
+ Authorization: `Bearer ${accessToken}`,
535
+ "ngrok-skip-browser-warning": true,
536
+ };
537
+ const response = await fetch(
538
+ `${url}?${new URLSearchParams(queryParams)}`,
539
+ {
540
+ method: "GET",
541
+ headers: { ...headers, ...newHeaders },
542
+ signal: cancellationToken?.signal
543
+ }
544
+ );
545
+ if (response.ok) {
546
+ const json: BaseReponseModel<string[]> =
547
+ (await response.json()) as BaseReponseModel<string[]>;
548
+ if (json.statusCode === ApiStatus.Success) {
549
+ return json.data;
550
+ } else {
551
+ console.error(
552
+ `Fail to generate presigned urls with message error: ${json.message}`
553
+ );
554
+ }
555
+ } else {
556
+ console.error(
557
+ `Fail to generate presigned urls with status ${response.statusText} and error: ${response.statusText}`
558
+ );
559
+ }
560
+
561
+ return null;
562
+ } catch (error) {
563
+ console.error(`Error when generate presigned urls: ${error}`);
564
+ }
565
+ }
566
+
567
+ public throwIfCancellationRequested(
568
+ cancellationToken: AbortController,
569
+ fileName: string
570
+ ) {
571
+ if (cancellationToken.signal.aborted) {
572
+ console.error(`${fileName} Cancellation requested.`);
573
+ cancellationToken.signal.throwIfAborted();
574
+ }
575
+ }
576
+
577
+ // public readFileBytes(file: Buffer, start: number, end: number): Buffer {
578
+ // const fileReader = file.subarray(start, end);
579
+ // return fileReader;
580
+ // }
581
+
582
+ public readFileBytes(file: File, start: number, end: number): Promise<ArrayBuffer> {
583
+ return new Promise((resolve, reject) => {
584
+ const blob = file.slice(start, end); // tạo blob từ phần file cần đọc
585
+ const reader = new FileReader();
586
+
587
+ reader.onload = () => {
588
+ if (reader.result instanceof ArrayBuffer) {
589
+ resolve(reader.result);
590
+ } else {
591
+ reject(new Error("Failed to read as ArrayBuffer"));
592
+ }
593
+ };
594
+
595
+ reader.onerror = () => reject(reader.error);
596
+ reader.readAsArrayBuffer(blob); // đọc phần blob thành ArrayBuffer
597
+ });
598
+ }
599
+
600
+ public async completeMultipartUpload(
601
+ bucketName: string,
602
+ fileName: string,
603
+ uploadId: string,
604
+ eTags: object,
605
+ accessToken?: string,
606
+ cancellationToken?: AbortController
607
+ ) {
608
+ try {
609
+ const url = `${Path.BaseURL}${Path.CompleteMultipartUpload}`;
610
+ const headers: any = {
611
+ Authorization: `Bearer ${accessToken}`,
612
+ "Content-Type": "application/json",
613
+ "ngrok-skip-browser-warning": true,
614
+ };
615
+
616
+ let body: any;
617
+ if (validString(bucketName)) {
618
+ body = { ...body, bucketName: bucketName };
619
+ }
620
+ if (validString(fileName)) {
621
+ body = { ...body, objectName: fileName };
622
+ }
623
+ if (validString(uploadId)) {
624
+ body = { ...body, uploadId: uploadId };
625
+ }
626
+ if (eTags) {
627
+ body = { ...body, eTags: eTags };
628
+ }
629
+ const bodyString = JSON.stringify(body);
630
+ const response = await fetch(url, {
631
+ method: "POST",
632
+ headers: headers,
633
+ body: bodyString,
634
+ signal: cancellationToken?.signal
635
+ });
636
+ if (response.ok) {
637
+ const json: BaseReponseModel<CompleteMultipartUploadResponse> =
638
+ (await response.json()) as BaseReponseModel<CompleteMultipartUploadResponse>;
639
+ if (json.statusCode === ApiStatus.Success) {
640
+ return json.data;
641
+ } else {
642
+ console.error(
643
+ `Fail to complete multiple part upload with message error: ${json.message}`
644
+ );
645
+ }
646
+ } else {
647
+ console.error(
648
+ `Fail to complete multiple part upload with status ${response.statusText} and error: ${response.statusText}`
649
+ );
650
+ }
651
+
652
+ return false;
653
+ } catch (error) {
654
+ console.error(`Error when complete multiple part upload: ${error}`);
655
+ }
656
+ }
657
+
658
+ public async generateMultiPresignedUrl(
659
+ bucketName: string,
660
+ filesName: string[],
661
+ accessToken?: string,
662
+ cancellationToken?: AbortController
663
+ ) {
664
+ try {
665
+ const url = `${Path.BaseURL}${Path.GenerateMultiPresignedURL}`;
666
+ // const url = `https://localhost:7193/api/Object/GenerateMultiPresignedURL`;
667
+ const headers: any = {
668
+ Authorization: `Bearer ${accessToken}`,
669
+ "Content-Type": "application/json",
670
+ "ngrok-skip-browser-warning": true,
671
+ };
672
+
673
+ const body = {
674
+ bucketName: bucketName,
675
+ objectNames: filesName,
676
+ setPermission: false
677
+ };
678
+ const bodyString = JSON.stringify(body);
679
+
680
+ const response = await fetch(url,
681
+ {
682
+ method: "POST",
683
+ headers: headers,
684
+ body: bodyString,
685
+ signal: cancellationToken?.signal
686
+ }
687
+ );
688
+ if (response.ok) {
689
+ const json: BaseReponseModel<MultiPresignURLResponse> =
690
+ (await response.json()) as BaseReponseModel<MultiPresignURLResponse>;
691
+ if (json.statusCode === ApiStatus.Success) {
692
+ return json.data;
693
+ } else {
694
+ console.error(
695
+ `Fail to generate multiple presigned url with message error: ${json.message}`
696
+ );
697
+ }
698
+ } else {
699
+ console.error(
700
+ `Fail to generate multiple presigned url with status ${response.statusText} and error: ${response.statusText}`
701
+ );
702
+ }
703
+
704
+ return null;
705
+ } catch (error) {
706
+ console.error(`Error when generate multiple presigned url: ${error}`);
707
+ }
708
+ }
709
+ //#endregion
710
+ }