import { assert } from 'oak-domain/lib/utils/assert'; import S3 from './s3'; import { S3SDK } from 'oak-external-sdk'; import { OakExternalException } from 'oak-domain/lib/types/Exception'; export default class S3Backend extends S3 { getConfigAndInstance(application, bucket) { const { config, account, endpoint, defaultBucket } = this.getConfig(application); const realBucket = bucket || defaultBucket; assert(realBucket, '没有指定上传桶,且配置中也没有默认上传桶'); // 在配置中找名称匹配的桶 const { buckets } = config; let bucketConfig = bucket ? buckets.find((ele) => ele.name === realBucket) : buckets[0]; const instance = S3SDK.getInstance(account.accessKey, account.secretKey, endpoint, bucketConfig?.zone || 'us-east-1'); return { config, instance, endpoint, }; } async composeFileUrlBackend(options) { const { application, extraFile, context, style } = options; const { config: s3CosConfig, endpoint } = this.getConfig(application); if (s3CosConfig) { let bucket = s3CosConfig.buckets.find((ele) => ele.name === extraFile.bucket); if (bucket) { const { domain, protocol, pathStyle } = bucket; let protocol2 = protocol; if (protocol instanceof Array) { const index = protocol.includes('https:') ? protocol.findIndex((ele) => ele === 'https:') : 0; protocol2 = protocol[index]; } const key = this.formKey(extraFile); // 如果使用 pathStyle (Minio 常用) if (pathStyle && endpoint) { return `${protocol2}//${domain}/${bucket.name}/${key}${style ? style : ''}`; } // 否则使用虚拟主机风格 (AWS S3 默认) return `${protocol2}//${domain}/${key}${style ? style : ''}`; } } return ''; } async formUploadMeta(application, extraFile) { const { bucket } = extraFile; const key = this.formKey(extraFile); const { instance, config: s3CosConfig, endpoint } = this.getConfigAndInstance(application, bucket); const { buckets } = s3CosConfig; let bucket2 = bucket; if (!bucket2) { const { defaultBucket } = s3CosConfig; bucket2 = defaultBucket; } assert(bucket2); const b = buckets.find((ele) => ele.name === bucket2); assert(b, `${bucket2}不是一个有效的桶配置`); try { const uploadInfo = await instance.getUploadInfo(bucket2, key, endpoint, b.pathStyle); Object.assign(extraFile, { bucket: bucket2, uploadMeta: uploadInfo, }); } catch (err) { throw new OakExternalException(`生成S3上传信息失败: ${err.message}`); } } async checkWhetherSuccess(application, extraFile) { const { bucket } = extraFile; const key = this.formKey(extraFile); const { instance, config: s3CosConfig, endpoint } = this.getConfigAndInstance(application, bucket); const b = s3CosConfig.buckets.find((ele) => ele.name === extraFile.bucket); assert(b, `extraFile中的bucket名称在S3配置中找不到「${extraFile.bucket}」`); try { const result = await instance.isExistObject(extraFile.bucket, key, endpoint, b.pathStyle); return result; } catch (err) { throw err; } } async removeFile(application, extraFile) { const { bucket } = extraFile; const key = this.formKey(extraFile); const { instance, config: s3CosConfig, endpoint } = this.getConfigAndInstance(application, bucket); const b = s3CosConfig.buckets.find((ele) => ele.name === extraFile.bucket); assert(b, `extraFile中的bucket名称在S3配置中找不到「${extraFile.bucket}」`); try { await instance.removeFile(extraFile.bucket, key, endpoint, b.pathStyle); } catch (err) { throw err; } } }