@cloudbase/manager-node 3.11.0 → 3.11.1-beta
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/lib/storage/index.js +53 -16
- package/package.json +1 -1
- package/src/storage/index.ts +66 -21
- package/types/storage/index.d.ts +15 -0
package/lib/storage/index.js
CHANGED
|
@@ -382,27 +382,32 @@ class StorageService {
|
|
|
382
382
|
* @returns {Promise<(NodeJS.ReadableStream | string)[]>}
|
|
383
383
|
*/
|
|
384
384
|
async downloadDirectory(options) {
|
|
385
|
-
const { cloudPath, localPath } = options;
|
|
385
|
+
const { cloudPath, localPath, parallel = 20 } = options;
|
|
386
386
|
const resolveLocalPath = path_1.default.resolve(localPath);
|
|
387
387
|
utils_1.checkFullAccess(resolveLocalPath, true);
|
|
388
388
|
const cloudDirectoryKey = this.getCloudKey(cloudPath);
|
|
389
389
|
const files = await this.walkCloudDir(cloudDirectoryKey);
|
|
390
|
-
const promises = files.map(async (
|
|
391
|
-
|
|
392
|
-
// 空路径和文件夹跳过
|
|
393
|
-
if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
const localFilePath = path_1.default.join(resolveLocalPath, fileRelativePath);
|
|
397
|
-
// 创建文件的父文件夹
|
|
398
|
-
const fileDir = path_1.default.dirname(localFilePath);
|
|
399
|
-
await make_dir_1.default(fileDir);
|
|
400
|
-
return this.downloadFile({
|
|
401
|
-
cloudPath: file.Key,
|
|
402
|
-
localPath: localFilePath
|
|
403
|
-
});
|
|
390
|
+
const promises = files.map(file => async () => {
|
|
391
|
+
return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath });
|
|
404
392
|
});
|
|
405
|
-
|
|
393
|
+
const asyncTaskController = new parallel_1.AsyncTaskParallelController(parallel, 50);
|
|
394
|
+
asyncTaskController.loadTasks(promises);
|
|
395
|
+
let res = await asyncTaskController.run();
|
|
396
|
+
const errorIndexArr = [];
|
|
397
|
+
res.map((item, index) => /Error/gi.test(Object.prototype.toString.call(item)) && errorIndexArr.push(index));
|
|
398
|
+
// 重试逻辑
|
|
399
|
+
if (errorIndexArr.length) {
|
|
400
|
+
const errorFiles = errorIndexArr.map(errorIndex => files[errorIndex]);
|
|
401
|
+
asyncTaskController.loadTasks(errorFiles.map(file => async () => {
|
|
402
|
+
return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath });
|
|
403
|
+
}));
|
|
404
|
+
res = await asyncTaskController.run();
|
|
405
|
+
}
|
|
406
|
+
const errorResultArr = this.determineDownLoadResultIsError(res);
|
|
407
|
+
if (errorResultArr.length) {
|
|
408
|
+
throw errorResultArr[0];
|
|
409
|
+
}
|
|
410
|
+
return res;
|
|
406
411
|
}
|
|
407
412
|
/**
|
|
408
413
|
* 列出文件夹下的文件
|
|
@@ -911,6 +916,38 @@ class StorageService {
|
|
|
911
916
|
}), interval);
|
|
912
917
|
}
|
|
913
918
|
}
|
|
919
|
+
/**
|
|
920
|
+
* 拼接路径下载单文件
|
|
921
|
+
* @param file
|
|
922
|
+
* @param cloudDirectoryKey
|
|
923
|
+
* @param resolveLocalPath
|
|
924
|
+
* @returns
|
|
925
|
+
*/
|
|
926
|
+
async downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath }) {
|
|
927
|
+
const fileRelativePath = file.Key.replace(cloudDirectoryKey, '');
|
|
928
|
+
// 空路径和文件夹跳过
|
|
929
|
+
if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
const localFilePath = path_1.default.join(resolveLocalPath, fileRelativePath);
|
|
933
|
+
// 创建文件的父文件夹
|
|
934
|
+
const fileDir = path_1.default.dirname(localFilePath);
|
|
935
|
+
await make_dir_1.default(fileDir);
|
|
936
|
+
return this.downloadFile({
|
|
937
|
+
cloudPath: file.Key,
|
|
938
|
+
localPath: localFilePath
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* 根据下载结果返回错误列表
|
|
943
|
+
* @param res
|
|
944
|
+
* @returns
|
|
945
|
+
*/
|
|
946
|
+
determineDownLoadResultIsError(res) {
|
|
947
|
+
const resultErrorArr = [];
|
|
948
|
+
res.map(item => /Error/gi.test(Object.prototype.toString.call(item)) && resultErrorArr.push(item));
|
|
949
|
+
return resultErrorArr;
|
|
950
|
+
}
|
|
914
951
|
}
|
|
915
952
|
__decorate([
|
|
916
953
|
utils_1.preLazy()
|
package/package.json
CHANGED
package/src/storage/index.ts
CHANGED
|
@@ -62,7 +62,6 @@ export interface IFilesOptions extends IOptions {
|
|
|
62
62
|
ignore?: string | string[]
|
|
63
63
|
// 文件列表
|
|
64
64
|
files: { localPath: string; cloudPath?: string }[]
|
|
65
|
-
|
|
66
65
|
// 重试次数
|
|
67
66
|
retryCount?: number
|
|
68
67
|
// 重试时间间隔(毫秒)
|
|
@@ -146,8 +145,8 @@ export class StorageService {
|
|
|
146
145
|
*/
|
|
147
146
|
@preLazy()
|
|
148
147
|
public async uploadFiles(options: IFilesOptions): Promise<void> {
|
|
149
|
-
const { files, onProgress, parallel, onFileFinish, ignore, retryCount,
|
|
150
|
-
|
|
148
|
+
const { files, onProgress, parallel, onFileFinish, ignore, retryCount, retryInterval } =
|
|
149
|
+
options
|
|
151
150
|
const { bucket, region } = this.getStorageConfig()
|
|
152
151
|
|
|
153
152
|
return this.uploadFilesCustom({
|
|
@@ -455,7 +454,6 @@ export class StorageService {
|
|
|
455
454
|
|
|
456
455
|
const cos = this.getCos(parallel)
|
|
457
456
|
const uploadFiles = Util.promisify(cos.uploadFiles).bind(cos)
|
|
458
|
-
|
|
459
457
|
const params = {
|
|
460
458
|
files: fileList,
|
|
461
459
|
SliceSize: BIG_FILE_SIZE,
|
|
@@ -567,32 +565,42 @@ export class StorageService {
|
|
|
567
565
|
public async downloadDirectory(options: {
|
|
568
566
|
cloudPath: string
|
|
569
567
|
localPath?: string
|
|
568
|
+
parallel?: number
|
|
570
569
|
}): Promise<(NodeJS.ReadableStream | string)[]> {
|
|
571
|
-
const { cloudPath, localPath } = options
|
|
570
|
+
const { cloudPath, localPath, parallel = 20 } = options
|
|
572
571
|
const resolveLocalPath = path.resolve(localPath)
|
|
573
572
|
|
|
574
573
|
checkFullAccess(resolveLocalPath, true)
|
|
575
574
|
|
|
576
575
|
const cloudDirectoryKey = this.getCloudKey(cloudPath)
|
|
577
576
|
const files = await this.walkCloudDir(cloudDirectoryKey)
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
const fileRelativePath = file.Key.replace(cloudDirectoryKey, '')
|
|
581
|
-
// 空路径和文件夹跳过
|
|
582
|
-
if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
|
|
583
|
-
return
|
|
584
|
-
}
|
|
585
|
-
const localFilePath = path.join(resolveLocalPath, fileRelativePath)
|
|
586
|
-
// 创建文件的父文件夹
|
|
587
|
-
const fileDir = path.dirname(localFilePath)
|
|
588
|
-
await makeDir(fileDir)
|
|
589
|
-
return this.downloadFile({
|
|
590
|
-
cloudPath: file.Key,
|
|
591
|
-
localPath: localFilePath
|
|
592
|
-
})
|
|
577
|
+
const promises = files.map(file => async () => {
|
|
578
|
+
return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath })
|
|
593
579
|
})
|
|
580
|
+
const asyncTaskController = new AsyncTaskParallelController(parallel, 50)
|
|
581
|
+
asyncTaskController.loadTasks(promises)
|
|
582
|
+
let res = await asyncTaskController.run()
|
|
583
|
+
const errorIndexArr = []
|
|
594
584
|
|
|
595
|
-
|
|
585
|
+
res.map(
|
|
586
|
+
(item, index) =>
|
|
587
|
+
/Error/gi.test(Object.prototype.toString.call(item)) && errorIndexArr.push(index)
|
|
588
|
+
)
|
|
589
|
+
// 重试逻辑
|
|
590
|
+
if (errorIndexArr.length) {
|
|
591
|
+
const errorFiles = errorIndexArr.map(errorIndex => files[errorIndex])
|
|
592
|
+
asyncTaskController.loadTasks(
|
|
593
|
+
errorFiles.map(file => async () => {
|
|
594
|
+
return this.downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath })
|
|
595
|
+
})
|
|
596
|
+
)
|
|
597
|
+
res = await asyncTaskController.run()
|
|
598
|
+
}
|
|
599
|
+
const errorResultArr = this.determineDownLoadResultIsError(res)
|
|
600
|
+
if (errorResultArr.length) {
|
|
601
|
+
throw errorResultArr[0]
|
|
602
|
+
}
|
|
603
|
+
return res
|
|
596
604
|
}
|
|
597
605
|
|
|
598
606
|
/**
|
|
@@ -1219,4 +1227,41 @@ export class StorageService {
|
|
|
1219
1227
|
)
|
|
1220
1228
|
}
|
|
1221
1229
|
}
|
|
1230
|
+
|
|
1231
|
+
/**
|
|
1232
|
+
* 拼接路径下载单文件
|
|
1233
|
+
* @param file
|
|
1234
|
+
* @param cloudDirectoryKey
|
|
1235
|
+
* @param resolveLocalPath
|
|
1236
|
+
* @returns
|
|
1237
|
+
*/
|
|
1238
|
+
private async downloadWithFilePath({ file, cloudDirectoryKey, resolveLocalPath }) {
|
|
1239
|
+
const fileRelativePath = file.Key.replace(cloudDirectoryKey, '')
|
|
1240
|
+
// 空路径和文件夹跳过
|
|
1241
|
+
if (!fileRelativePath || /\/$/g.test(fileRelativePath)) {
|
|
1242
|
+
return
|
|
1243
|
+
}
|
|
1244
|
+
const localFilePath = path.join(resolveLocalPath, fileRelativePath)
|
|
1245
|
+
// 创建文件的父文件夹
|
|
1246
|
+
const fileDir = path.dirname(localFilePath)
|
|
1247
|
+
await makeDir(fileDir)
|
|
1248
|
+
return this.downloadFile({
|
|
1249
|
+
cloudPath: file.Key,
|
|
1250
|
+
localPath: localFilePath
|
|
1251
|
+
})
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* 根据下载结果返回错误列表
|
|
1256
|
+
* @param res
|
|
1257
|
+
* @returns
|
|
1258
|
+
*/
|
|
1259
|
+
private determineDownLoadResultIsError(res) {
|
|
1260
|
+
const resultErrorArr = []
|
|
1261
|
+
res.map(
|
|
1262
|
+
item =>
|
|
1263
|
+
/Error/gi.test(Object.prototype.toString.call(item)) && resultErrorArr.push(item)
|
|
1264
|
+
)
|
|
1265
|
+
return resultErrorArr
|
|
1266
|
+
}
|
|
1222
1267
|
}
|
package/types/storage/index.d.ts
CHANGED
|
@@ -151,6 +151,7 @@ export declare class StorageService {
|
|
|
151
151
|
downloadDirectory(options: {
|
|
152
152
|
cloudPath: string;
|
|
153
153
|
localPath?: string;
|
|
154
|
+
parallel?: number;
|
|
154
155
|
}): Promise<(NodeJS.ReadableStream | string)[]>;
|
|
155
156
|
/**
|
|
156
157
|
* 列出文件夹下的文件
|
|
@@ -305,5 +306,19 @@ export declare class StorageService {
|
|
|
305
306
|
* @returns
|
|
306
307
|
*/
|
|
307
308
|
private uploadFilesWithRetry;
|
|
309
|
+
/**
|
|
310
|
+
* 拼接路径下载单文件
|
|
311
|
+
* @param file
|
|
312
|
+
* @param cloudDirectoryKey
|
|
313
|
+
* @param resolveLocalPath
|
|
314
|
+
* @returns
|
|
315
|
+
*/
|
|
316
|
+
private downloadWithFilePath;
|
|
317
|
+
/**
|
|
318
|
+
* 根据下载结果返回错误列表
|
|
319
|
+
* @param res
|
|
320
|
+
* @returns
|
|
321
|
+
*/
|
|
322
|
+
private determineDownLoadResultIsError;
|
|
308
323
|
}
|
|
309
324
|
export {};
|