@cloudbase/storage 2.23.3 → 2.24.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.
package/src/storage.ts ADDED
@@ -0,0 +1,698 @@
1
+ import { constants, utils, helpers } from '@cloudbase/utilities'
2
+
3
+ import {
4
+ ICloudbaseFileMetaDataRes,
5
+ ICloudbaseFileInfo,
6
+ ICloudbaseUploadFileParams,
7
+ ICloudbaseUploadFileResult,
8
+ ICloudbaseGetUploadMetadataParams,
9
+ ICloudbaseDeleteFileParams,
10
+ ICloudbaseDeleteFileResult,
11
+ ICloudbaseGetTempFileURLResult,
12
+ ICloudbaseGetTempFileURLParams,
13
+ ICloudbaseDownloadFileResult,
14
+ ICloudbaseDownloadFileParams,
15
+ ICloudbaseCopyFileParams,
16
+ ICloudbaseCopyFileResult,
17
+ } from '@cloudbase/types/storage'
18
+
19
+ enum EUploadMethod {
20
+ put = 'put',
21
+ post = 'post',
22
+ }
23
+
24
+ interface IUploadMetadata {
25
+ url: string
26
+ token: string
27
+ authorization: string
28
+ fileId: string
29
+ cosFileId: string
30
+ download_url?: string
31
+ }
32
+
33
+ const { getSdkName, ERRORS, COMMUNITY_SITE_URL } = constants
34
+ const { isArray, isString, isPalinObject, execCallback } = utils
35
+ const { catchErrorsDecorator } = helpers
36
+
37
+ export const COMPONENT_NAME = 'storage'
38
+
39
+ // function basename(path) {
40
+ // const lastSlashIndex = path.lastIndexOf('/')
41
+ // if (lastSlashIndex === -1) return path
42
+ // return path.slice(lastSlashIndex + 1)
43
+ // }
44
+
45
+ const storageGateWay = {
46
+ getUploadInfo: async (
47
+ request,
48
+ params: { path: string; headers?: Record<string, string> },
49
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
50
+ ) => {
51
+ let res = await request.gateWay(
52
+ {
53
+ path: 'storages',
54
+ name: 'get-objects-upload-info',
55
+ data: [
56
+ {
57
+ objectId: params.path,
58
+ ...(params.headers ? { signedHeader: params.headers } : {}),
59
+ },
60
+ ],
61
+ },
62
+ customReqOpts,
63
+ )
64
+ const data = res.data?.[0] || {}
65
+
66
+ res = {
67
+ ...res,
68
+ data: {
69
+ ...(data.code ? { ...data } : {}),
70
+ authorization: data.authorization,
71
+ token: data.token,
72
+ url: data.uploadUrl,
73
+ fileId: data.cloudObjectId,
74
+ cosFileId: data.cloudObjectMeta,
75
+ download_url: data.downloadUrl,
76
+ },
77
+ }
78
+
79
+ return res
80
+ },
81
+ getDownLoadInfo: async (
82
+ request,
83
+ params: { convertedFileList: Array<{ fileid: string }> },
84
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
85
+ ) => {
86
+ let res = await request.gateWay(
87
+ {
88
+ path: 'storages',
89
+ name: 'get-objects-download-info',
90
+ data: params.convertedFileList.map((v: any) => ({ cloudObjectId: v.fileid })),
91
+ },
92
+ customReqOpts,
93
+ )
94
+ res = {
95
+ ...res,
96
+ data: {
97
+ download_list: res.data?.map(v => ({
98
+ code: v.code || 'SUCCESS',
99
+ message: v.message,
100
+ fileid: v.cloudObjectId,
101
+ download_url: v.downloadUrl,
102
+ fileID: v.cloudObjectId,
103
+ tempFileURL: v.downloadUrl,
104
+ })),
105
+ },
106
+ }
107
+
108
+ return res
109
+ },
110
+ delete: async (
111
+ request,
112
+ params: { fileList: Array<string> },
113
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
114
+ ) => {
115
+ let res = await request.gateWay(
116
+ {
117
+ path: 'storages',
118
+ name: 'delete-objects',
119
+ data: params.fileList.map(v => ({ cloudObjectId: v })),
120
+ },
121
+ customReqOpts,
122
+ )
123
+ res = {
124
+ ...res,
125
+ data: {
126
+ delete_list: res.data?.map(v => ({
127
+ code: v.code || 'SUCCESS',
128
+ fileID: v.cloudObjectId,
129
+ message: v.message,
130
+ })),
131
+ },
132
+ }
133
+
134
+ return res
135
+ },
136
+ copyFile: async (
137
+ request,
138
+ params: {
139
+ convertedFileList: Array<{ src_path: string; dst_path: string; overwrite: boolean; remove_original: boolean }>
140
+ },
141
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
142
+ ) => {
143
+ let res = await request.gateWay(
144
+ {
145
+ path: 'storages',
146
+ name: 'copy-objects',
147
+ data: params.convertedFileList.map((v: any) => ({
148
+ srcPath: v.src_path,
149
+ dstPath: v.dst_path,
150
+ overwrite: v.overwrite,
151
+ removeOriginal: v.remove_original,
152
+ })),
153
+ },
154
+ customReqOpts,
155
+ )
156
+ res = {
157
+ ...res,
158
+ data: {
159
+ copy_list: res.data?.map(v => ({
160
+ code: v.code || 'SUCCESS',
161
+ fileID: v.cloudObjectId,
162
+ message: v.message,
163
+ })),
164
+ },
165
+ }
166
+
167
+ return res
168
+ },
169
+ }
170
+
171
+ export interface ICloudbaseContext {
172
+ config: any
173
+ request: any
174
+ }
175
+
176
+ export class CloudbaseStorage {
177
+ private context?: ICloudbaseContext
178
+ constructor(context?: ICloudbaseContext) {
179
+ this.context = context
180
+ }
181
+
182
+ get config() {
183
+ // @ts-ignore
184
+ return this.context?.config
185
+ }
186
+
187
+ get request() {
188
+ // @ts-ignore
189
+ return this.context?.request
190
+ }
191
+
192
+ public isGateWay() {
193
+ // @ts-ignore
194
+ const { config } = this
195
+ const endPointMode = config.endPointMode || 'CLOUD_API'
196
+
197
+ return endPointMode === 'GATEWAY'
198
+ }
199
+
200
+ @catchErrorsDecorator({
201
+ customInfo: {
202
+ className: 'Cloudbase',
203
+ methodName: 'uploadFile',
204
+ },
205
+ title: '上传文件失败',
206
+ messages: [
207
+ '请确认以下各项:',
208
+ ' 1 - 调用 uploadFile() 的语法或参数是否正确',
209
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
210
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
211
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
212
+ ],
213
+ })
214
+ public async uploadFile(
215
+ params: Omit<ICloudbaseUploadFileParams, 'filePath'> & { filePath?: string },
216
+ callback?: Function,
217
+ ): Promise<ICloudbaseUploadFileResult> {
218
+ const { cloudPath, filePath, onUploadProgress, method = 'put', headers = {}, fileContent } = params
219
+ if (!isString(cloudPath) || (!filePath && !fileContent)) {
220
+ throw new Error(JSON.stringify({
221
+ code: ERRORS.INVALID_PARAMS,
222
+ msg: `[${COMPONENT_NAME}.uploadFile] invalid params`,
223
+ }),)
224
+ }
225
+ const uploadMethod = { put: EUploadMethod.put, post: EUploadMethod.post }[method.toLocaleLowerCase()] || EUploadMethod.put
226
+
227
+ // 调用 getUploadMetadata 获取上传元数据
228
+ const metadataResult = await this.getUploadMetadata({
229
+ cloudPath,
230
+ method: uploadMethod,
231
+ headers: uploadMethod === EUploadMethod.put ? headers : undefined,
232
+ customReqOpts: params.customReqOpts,
233
+ })
234
+
235
+ const { data: metadata, requestId } = metadataResult
236
+ const { url, authorization, token, fileId, cosFileId, download_url: downloadUrl } = metadata
237
+
238
+ const commonParams = {
239
+ url,
240
+ file: filePath,
241
+ name: cloudPath,
242
+ onUploadProgress,
243
+ fileContent,
244
+ fileId,
245
+ requestId,
246
+ }
247
+
248
+ const putParams = {
249
+ ...commonParams,
250
+ method: EUploadMethod.put,
251
+ headers: {
252
+ ...headers,
253
+ authorization,
254
+ 'x-cos-meta-fileid': cosFileId,
255
+ 'x-cos-security-token': token,
256
+ },
257
+ }
258
+
259
+ const postParams = {
260
+ ...commonParams,
261
+ method: EUploadMethod.post,
262
+ data: {
263
+ key: cloudPath,
264
+ signature: authorization,
265
+ 'x-cos-meta-fileid': cosFileId,
266
+ success_action_status: '201',
267
+ 'x-cos-security-token': token,
268
+ },
269
+ }
270
+
271
+ const uploadConfig = {
272
+ [EUploadMethod.put]: {
273
+ params: putParams,
274
+ isSuccess: (code: number) => code >= 200 && code < 300,
275
+ },
276
+ [EUploadMethod.post]: {
277
+ params: postParams,
278
+ isSuccess: (code: number) => code === 201,
279
+ },
280
+ }
281
+
282
+ // @ts-ignore
283
+ const res = await this.request.upload(uploadConfig[uploadMethod].params)
284
+
285
+ if (uploadConfig[uploadMethod].isSuccess(res.statusCode)) {
286
+ return execCallback(callback, null, {
287
+ fileID: fileId,
288
+ download_url: downloadUrl,
289
+ requestId,
290
+ })
291
+ }
292
+ return execCallback(
293
+ callback,
294
+ new Error(`[${getSdkName()}][${ERRORS.OPERATION_FAIL}][${COMPONENT_NAME}]:${res.data}`),
295
+ )
296
+ }
297
+ @catchErrorsDecorator({
298
+ customInfo: {
299
+ className: 'Cloudbase',
300
+ methodName: 'getUploadMetadata',
301
+ },
302
+ title: '获取上传元信息失败',
303
+ messages: [
304
+ '请确认以下各项:',
305
+ ' 1 - 调用 getUploadMetadata() 的语法或参数是否正确',
306
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
307
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
308
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
309
+ ],
310
+ })
311
+ public async getUploadMetadata(
312
+ params: ICloudbaseGetUploadMetadataParams & {
313
+ method?: EUploadMethod
314
+ headers?: Record<string, string>
315
+ },
316
+ callback?: Function,
317
+ ): Promise<{ data: IUploadMetadata; requestId: string }> {
318
+ const { cloudPath, method, headers } = params
319
+ if (!isString(cloudPath)) {
320
+ throw new Error(JSON.stringify({
321
+ code: ERRORS.INVALID_PARAMS,
322
+ msg: `[${COMPONENT_NAME}.getUploadMetadata] invalid cloudPath`,
323
+ }),)
324
+ }
325
+ // @ts-ignore
326
+ const { request } = this
327
+ const action = 'storage.getUploadMetadata'
328
+
329
+ try {
330
+ let metaData: ICloudbaseFileMetaDataRes
331
+
332
+ const metaDataParam: {
333
+ path: string
334
+ method?: EUploadMethod
335
+ headers?: Record<string, string>
336
+ } = { path: cloudPath }
337
+
338
+ if (method) {
339
+ metaDataParam.method = method
340
+ }
341
+ if (method === EUploadMethod.put && headers) {
342
+ metaDataParam.headers = headers
343
+ }
344
+
345
+ if (this.isGateWay()) {
346
+ metaData = await storageGateWay.getUploadInfo(request, metaDataParam, params.customReqOpts)
347
+ } else {
348
+ metaData = await request.send(action, metaDataParam, params.customReqOpts)
349
+ }
350
+ return execCallback(callback, null, metaData)
351
+ } catch (err) {
352
+ return execCallback(callback, err)
353
+ }
354
+ }
355
+ @catchErrorsDecorator({
356
+ customInfo: {
357
+ className: 'Cloudbase',
358
+ methodName: 'deleteFile',
359
+ },
360
+ title: '删除文件失败',
361
+ messages: [
362
+ '请确认以下各项:',
363
+ ' 1 - 调用 deleteFile() 的语法或参数是否正确',
364
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
365
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
366
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
367
+ ],
368
+ })
369
+ public async deleteFile(
370
+ params: ICloudbaseDeleteFileParams,
371
+ callback?: Function,
372
+ ): Promise<ICloudbaseDeleteFileResult> {
373
+ const { fileList } = params
374
+
375
+ if (!fileList || !isArray(fileList) || fileList.length === 0) {
376
+ throw new Error(JSON.stringify({
377
+ code: ERRORS.INVALID_PARAMS,
378
+ msg: `[${COMPONENT_NAME}.deleteFile] fileList must not be empty`,
379
+ }),)
380
+ }
381
+
382
+ for (const fileId of fileList) {
383
+ if (!fileId || !isString(fileId)) {
384
+ throw new Error(JSON.stringify({
385
+ code: ERRORS.INVALID_PARAMS,
386
+ msg: `[${COMPONENT_NAME}.deleteFile] fileID must be string`,
387
+ }),)
388
+ }
389
+ }
390
+
391
+ const action = 'storage.batchDeleteFile'
392
+ // @ts-ignore
393
+ const { request } = this
394
+ let res: any = {}
395
+
396
+ if (this.isGateWay()) {
397
+ res = await storageGateWay.delete(request, { fileList }, params.customReqOpts)
398
+ } else {
399
+ res = await request.send(
400
+ action,
401
+ {
402
+ fileid_list: fileList,
403
+ },
404
+ params.customReqOpts,
405
+ )
406
+ }
407
+
408
+ if (res.code) {
409
+ return execCallback(callback, null, res)
410
+ }
411
+ const data = {
412
+ fileList: res.data.delete_list,
413
+ requestId: res.requestId,
414
+ }
415
+ return execCallback(callback, null, data)
416
+ }
417
+ @catchErrorsDecorator({
418
+ customInfo: {
419
+ className: 'Cloudbase',
420
+ methodName: 'getTempFileURL',
421
+ },
422
+ title: '获取文件下载链接',
423
+ messages: [
424
+ '请确认以下各项:',
425
+ ' 1 - 调用 getTempFileURL() 的语法或参数是否正确',
426
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
427
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
428
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
429
+ ],
430
+ })
431
+ public async getTempFileURL(
432
+ params: ICloudbaseGetTempFileURLParams,
433
+ callback?: Function,
434
+ ): Promise<ICloudbaseGetTempFileURLResult> {
435
+ const { fileList } = params
436
+
437
+ if (!fileList || !isArray(fileList) || fileList.length === 0) {
438
+ throw new Error(JSON.stringify({
439
+ code: ERRORS.INVALID_PARAMS,
440
+ msg: `[${COMPONENT_NAME}.getTempFileURL] fileList must not be empty`,
441
+ }),)
442
+ }
443
+
444
+ const convertedFileList = []
445
+ for (const file of fileList) {
446
+ if (isPalinObject(file)) {
447
+ if (!Object.prototype.hasOwnProperty.call(file, 'fileID')) {
448
+ throw new Error(JSON.stringify({
449
+ code: ERRORS.INVALID_PARAMS,
450
+ msg: `[${COMPONENT_NAME}.getTempFileURL] file info must include fileID`,
451
+ }),)
452
+ }
453
+
454
+ convertedFileList.push({
455
+ fileid: (file as ICloudbaseFileInfo).fileID,
456
+ max_age: (file as ICloudbaseFileInfo).maxAge || 7200,
457
+ })
458
+ } else if (isString(file)) {
459
+ convertedFileList.push({
460
+ fileid: file,
461
+ })
462
+ } else {
463
+ throw new Error(JSON.stringify({
464
+ code: ERRORS.INVALID_PARAMS,
465
+ msg: `[${COMPONENT_NAME}.getTempFileURL] invalid fileList`,
466
+ }),)
467
+ }
468
+ }
469
+
470
+ const action = 'storage.batchGetDownloadUrl'
471
+ // @ts-ignore
472
+ const { request } = this
473
+ let res: any = {}
474
+
475
+ if (this.isGateWay()) {
476
+ res = await storageGateWay.getDownLoadInfo(request, { convertedFileList }, params.customReqOpts)
477
+ } else {
478
+ res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)
479
+ }
480
+
481
+ if (res.code) {
482
+ return execCallback(callback, null, res)
483
+ }
484
+
485
+ return execCallback(callback, null, {
486
+ fileList: res.data.download_list,
487
+ requestId: res.requestId,
488
+ })
489
+ }
490
+ @catchErrorsDecorator({
491
+ customInfo: {
492
+ className: 'Cloudbase',
493
+ methodName: 'downloadFile',
494
+ },
495
+ title: '下载文件失败',
496
+ messages: [
497
+ '请确认以下各项:',
498
+ ' 1 - 调用 downloadFile() 的语法或参数是否正确',
499
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
500
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
501
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
502
+ ],
503
+ })
504
+ public async downloadFile(
505
+ params: ICloudbaseDownloadFileParams,
506
+ callback?: Function,
507
+ ): Promise<ICloudbaseDownloadFileResult> {
508
+ const { fileID } = params
509
+ if (!isString(fileID)) {
510
+ throw new Error(JSON.stringify({
511
+ code: ERRORS.INVALID_PARAMS,
512
+ msg: `[${COMPONENT_NAME}.getTempFileURL] fileID must be string`,
513
+ }),)
514
+ }
515
+
516
+ const tmpUrlRes = await this.getTempFileURL.call(this, {
517
+ fileList: [
518
+ {
519
+ fileID,
520
+ maxAge: 600,
521
+ },
522
+ ],
523
+ customReqOpts: params.customReqOpts,
524
+ })
525
+
526
+ const res = tmpUrlRes.fileList[0]
527
+
528
+ if (res.code !== 'SUCCESS') {
529
+ return execCallback(callback, res)
530
+ }
531
+ // @ts-ignore
532
+ const { request } = this
533
+
534
+ const tmpUrl = encodeURI(res.download_url)
535
+
536
+ const result = await request.download({ url: tmpUrl, tempFilePath: params.tempFilePath })
537
+ return execCallback(callback, null, result)
538
+ }
539
+ @catchErrorsDecorator({
540
+ customInfo: {
541
+ className: 'Cloudbase',
542
+ methodName: 'copyFile',
543
+ },
544
+ title: '批量复制文件',
545
+ messages: [
546
+ '请确认以下各项:',
547
+ ' 1 - 调用 copyFile() 的语法或参数是否正确',
548
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
549
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
550
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
551
+ ],
552
+ })
553
+ public async copyFile(params: ICloudbaseCopyFileParams, callback?: Function): Promise<ICloudbaseCopyFileResult> {
554
+ const { fileList } = params
555
+
556
+ if (!fileList || !isArray(fileList) || fileList.length === 0) {
557
+ throw new Error(JSON.stringify({
558
+ code: ERRORS.INVALID_PARAMS,
559
+ msg: `[${COMPONENT_NAME}.copyFile] fileList must not be empty`,
560
+ }),)
561
+ }
562
+
563
+ const convertedFileList = []
564
+
565
+ for (const file of fileList) {
566
+ const { srcPath, dstPath } = file
567
+ if (!srcPath || !dstPath || typeof srcPath !== 'string' || typeof dstPath !== 'string') {
568
+ throw new Error(JSON.stringify({
569
+ code: ERRORS.INVALID_PARAMS,
570
+ msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath may not be empty`,
571
+ }),)
572
+ }
573
+ if (srcPath === dstPath) {
574
+ throw new Error(JSON.stringify({
575
+ code: ERRORS.INVALID_PARAMS,
576
+ msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath can not be the same`,
577
+ }),)
578
+ }
579
+ // if (basename(srcPath) !== basename(dstPath)) {
580
+ // throw new Error(JSON.stringify({
581
+ // code: ERRORS.INVALID_PARAMS,
582
+ // msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath file name must be the same`,
583
+ // }),)
584
+ // }
585
+ convertedFileList.push({
586
+ src_path: srcPath,
587
+ dst_path: dstPath,
588
+ overwrite: file.overwrite,
589
+ remove_original: file.removeOriginal,
590
+ })
591
+ }
592
+
593
+ // @ts-ignore
594
+ const { request } = this
595
+ let res: any = {}
596
+
597
+ if (this.isGateWay()) {
598
+ res = await storageGateWay.copyFile(request, { convertedFileList }, params.customReqOpts)
599
+ } else {
600
+ const action = 'storage.batchCopyFile'
601
+ res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)
602
+ }
603
+
604
+ if (res.code) {
605
+ return execCallback(callback, null, res)
606
+ }
607
+
608
+ return execCallback(callback, null, {
609
+ fileList: res.data.copy_list,
610
+ requestId: res.requestId,
611
+ })
612
+ }
613
+
614
+ public async getFileInfo(params: ICloudbaseGetTempFileURLParams): Promise<{
615
+ fileList: (Pick<ICloudbaseGetTempFileURLResult['fileList'][0], 'code' | 'fileID' | 'tempFileURL' | 'message'> & {
616
+ fileName?: string
617
+ cloudId?: ICloudbaseGetTempFileURLResult['fileList'][0]['fileID']
618
+ contentType?: string
619
+ mime?: string
620
+ size?: number
621
+ cacheControl?: string
622
+ lastModified?: string
623
+ etag?: string
624
+ })[]
625
+ requestId: string
626
+ }> {
627
+ const fileInfo = await this.getTempFileURL(params)
628
+
629
+ if (fileInfo?.fileList && fileInfo?.fileList?.length > 0) {
630
+ const fileList = await Promise.all(fileInfo.fileList.map(async (item: ICloudbaseGetTempFileURLResult['fileList'][0]) => {
631
+ if (item.code !== 'SUCCESS') {
632
+ return {
633
+ code: item.code,
634
+ fileID: item.fileID,
635
+ tempFileURL: item.tempFileURL,
636
+ message: item.message,
637
+ }
638
+ }
639
+
640
+ try {
641
+ // @ts-ignore
642
+ const { request } = this
643
+ const res = await request.fetch({ url: item.tempFileURL, method: 'HEAD' })
644
+ let { header } = res
645
+
646
+ if (Headers && header instanceof Headers) {
647
+ header = Object.fromEntries(res.header.entries())
648
+ }
649
+ // eslint-disable-next-line radix
650
+ const fileSize = parseInt(header['content-length']) || 0
651
+ const contentType = header['content-type'] || ''
652
+
653
+ if ([400, 404].includes(Number(res.statusCode))) {
654
+ return {
655
+ code: 'FILE_NOT_FOUND',
656
+ fileID: item.fileID,
657
+ tempFileURL: item.tempFileURL,
658
+ message: 'file not found',
659
+ }
660
+ }
661
+
662
+ const fileInfo = {
663
+ code: item.code,
664
+ fileID: item.fileID,
665
+ tempFileURL: item.tempFileURL,
666
+ cloudId: item.fileID,
667
+ fileName: item.fileID.split('/').pop(),
668
+ contentType,
669
+ mime: contentType.split(';')[0].trim(),
670
+ size: fileSize,
671
+ etag: header.etag || '',
672
+ lastModified: header['last-modified'] || '',
673
+ cacheControl: header['cache-control'] || '',
674
+ }
675
+
676
+ return fileInfo
677
+ } catch (e) {
678
+ return {
679
+ code: 'FETCH_FILE_INFO_ERROR',
680
+ fileID: item.fileID,
681
+ tempFileURL: item.tempFileURL,
682
+ message: e.message,
683
+ }
684
+ }
685
+ }),)
686
+
687
+ return {
688
+ fileList,
689
+ requestId: fileInfo.requestId,
690
+ }
691
+ }
692
+
693
+ return {
694
+ fileList: [],
695
+ requestId: fileInfo.requestId,
696
+ }
697
+ }
698
+ }