151 lines
7.0 KiB
JavaScript
151 lines
7.0 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
const tslib_1 = require("tslib");
|
||
const assert_1 = require("oak-domain/lib/utils/assert");
|
||
const s3_1 = tslib_1.__importDefault(require("./s3"));
|
||
const oak_external_sdk_1 = require("oak-external-sdk");
|
||
const Exception_1 = require("oak-domain/lib/types/Exception");
|
||
class S3Backend extends s3_1.default {
|
||
getConfigAndInstance(application, bucket) {
|
||
const { config, account, endpoint, defaultBucket } = this.getConfig(application);
|
||
const realBucket = bucket || defaultBucket;
|
||
(0, assert_1.assert)(realBucket, '没有指定上传桶,且配置中也没有默认上传桶');
|
||
// 在配置中找名称匹配的桶
|
||
const { buckets } = config;
|
||
let bucketConfig = bucket
|
||
? buckets.find((ele) => ele.name === realBucket)
|
||
: buckets[0];
|
||
const instance = oak_external_sdk_1.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;
|
||
}
|
||
(0, assert_1.assert)(bucket2);
|
||
const b = buckets.find((ele) => ele.name === bucket2);
|
||
(0, assert_1.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 Exception_1.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);
|
||
(0, assert_1.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);
|
||
(0, assert_1.assert)(b, `extraFile中的bucket名称在S3配置中找不到「${extraFile.bucket}」`);
|
||
try {
|
||
await instance.removeFile(extraFile.bucket, key, endpoint, b.pathStyle);
|
||
}
|
||
catch (err) {
|
||
throw err;
|
||
}
|
||
}
|
||
async composeChunkUploadInfo(application, extraFile, context) {
|
||
const key = this.formKey(extraFile);
|
||
const { instance, config: s3Config } = this.getConfigAndInstance(application, extraFile.bucket);
|
||
const preInit = await instance.prepareMultipartUpload(extraFile.bucket, key, extraFile.chunkInfo?.partCount, {
|
||
endpoint: s3Config.endpoint,
|
||
expiresIn: 30000, // 上传链接过期时间,单位秒
|
||
});
|
||
return {
|
||
uploadId: preInit.uploadId,
|
||
chunkSize: extraFile.chunkInfo?.chunkSize,
|
||
partCount: preInit.parts.length,
|
||
parts: preInit.parts.map((part) => ({
|
||
partNumber: part.partNumber,
|
||
uploadUrl: part.uploadUrl,
|
||
formData: {}, // S3不需要额外的formData
|
||
})),
|
||
};
|
||
}
|
||
/**
|
||
* 完成分片上传后的合并操作
|
||
*/
|
||
async mergeChunkedUpload(application, extraFile, context) {
|
||
const key = this.formKey(extraFile);
|
||
const { instance, config: s3CosConfig } = this.getConfigAndInstance(application, extraFile.bucket);
|
||
await instance.completeMultipartUpload(extraFile.bucket, key, extraFile.chunkInfo.uploadId, extraFile.chunkInfo.parts.map((part) => ({
|
||
partNumber: part.partNumber,
|
||
eTag: part.etag,
|
||
})), s3CosConfig.endpoint);
|
||
}
|
||
async abortMultipartUpload(application, extraFile, context) {
|
||
const key = this.formKey(extraFile);
|
||
const { instance, config: s3CosConfig } = this.getConfigAndInstance(application, extraFile.bucket);
|
||
await instance.abortMultipartUpload(extraFile.bucket, key, extraFile.chunkInfo.uploadId, s3CosConfig.endpoint);
|
||
}
|
||
async listMultipartUploads(application, extraFile, context) {
|
||
const key = this.formKey(extraFile);
|
||
const { instance, config: s3CosConfig } = this.getConfigAndInstance(application, extraFile.bucket);
|
||
const result = await instance.listParts(extraFile.bucket, key, extraFile.chunkInfo.uploadId, s3CosConfig.endpoint, 101);
|
||
(0, assert_1.assert)(result.isTruncated === false, `分片数量超过101,无法列出所有分片信息,不应当出现这个情况,触发器中已经限制了最大分片数量为100`);
|
||
return {
|
||
parts: result.parts.map((part) => ({
|
||
partNumber: part.partNumber,
|
||
etag: part.eTag,
|
||
size: part.size,
|
||
lastModified: part.lastModified,
|
||
}))
|
||
};
|
||
}
|
||
}
|
||
exports.default = S3Backend;
|