@mt-utils/huawei-obs
Version:
华为云OBS文件上传下载
324 lines (323 loc) • 10.4 kB
JavaScript
var l = Object.defineProperty;
var g = (r, t, s) => t in r ? l(r, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : r[t] = s;
var i = (r, t, s) => g(r, typeof t != "symbol" ? t + "" : t, s);
import { checkEmpty as C } from "@mt-utils/tools";
import O from "esdk-obs-browserjs";
var o = /* @__PURE__ */ ((r) => (r[r.UPLOAD_NETWORK_ERROR = 10001] = "UPLOAD_NETWORK_ERROR", r[r.SLICE_UPLOAD_INIT_ERROR = 10002] = "SLICE_UPLOAD_INIT_ERROR", r[r.SLICE_UPLOAD_UPLOAD_ERROR = 10003] = "SLICE_UPLOAD_UPLOAD_ERROR", r[r.SLICE_UPLOAD_MERGE_ERROR = 10005] = "SLICE_UPLOAD_MERGE_ERROR", r[r.SLICE_UPLOAD_ABORT_ERROR = 10006] = "SLICE_UPLOAD_ABORT_ERROR", r))(o || {});
const D = {
[o.UPLOAD_NETWORK_ERROR]: "请求失败,请检查网络",
[o.SLICE_UPLOAD_INIT_ERROR]: "初始化文件分片失败,请检查文件",
[o.SLICE_UPLOAD_UPLOAD_ERROR]: "上传文件分片失败,请检查文件",
[o.SLICE_UPLOAD_MERGE_ERROR]: "合并文件失败,请检查文件",
[o.SLICE_UPLOAD_ABORT_ERROR]: "取消上传失败,请检查文件"
};
class h extends Error {
constructor(s, e) {
super(s);
i(this, "code");
this.name = "ObsError", this.code = e;
}
static create(s, e) {
return new h(
(D == null ? void 0 : D[s]) ?? e ?? "未知错误",
s
);
}
}
var S = /* @__PURE__ */ ((r) => (r.READY = "ready", r.UPLOADING = "uploading", r.SUCCESS = "success", r.ERROR = "error", r.ABORT = "abort", r))(S || {});
const N = {
partSize: 1024 * 1024 * 1
};
class T {
/**
* 构造函数,初始化OBS客户端实例和上传选项。
* @param obsClient OBS客户端实例
* @param uploadOptions 上传选项
*/
constructor(t, s) {
/**
* OBS客户端实例。
*/
i(this, "obsClient");
/**
* 分片上传选项,包含文件上下文选项和事件回调。
*/
i(this, "uploadOptions");
/**
* 上传ID,用于标识当前上传任务的唯一性。
*/
i(this, "uploadId");
/**
* 是否已经取消上传。
*/
i(this, "uploadStatus");
this.obsClient = t, this.uploadOptions = Object.assign(this, N, s), this.exec();
}
/**
* 执行分片上传流程。
*/
async exec() {
var t, s, e, u, R, n, a, _, E, P, A, c;
try {
this.uploadStatus = S.READY, (s = (t = this.uploadOptions) == null ? void 0 : t.onStart) == null || s.call(t), this.uploadStatus = S.UPLOADING, (u = (e = this.uploadOptions) == null ? void 0 : e.onProgress) == null || u.call(e, { percent: 0 });
const I = await this.generateUploadId();
this.uploadId = I;
const m = this.generateFileParts(
this.uploadOptions.sourceFile.size,
this.uploadOptions.partSize
);
this.wathcUploadFileProgress();
const f = await this.uploadFileParts(m);
await this.mergeFileParts(f), (n = (R = this.uploadOptions) == null ? void 0 : R.onProgress) == null || n.call(R, { percent: 100 }), this.uploadStatus = S.SUCCESS, (_ = (a = this.uploadOptions) == null ? void 0 : a.onSuccess) == null || _.call(a, {
sourceFile: this.uploadOptions.sourceFile,
fileDir: this.uploadOptions.fileDir || ""
});
} catch (I) {
if (this.shouldAbort())
return;
this.uploadStatus = S.ERROR, (P = (E = this.uploadOptions) == null ? void 0 : E.onError) == null || P.call(E, I);
} finally {
(c = (A = this.uploadOptions) == null ? void 0 : A.onFinally) == null || c.call(A);
}
}
/**
* 生成上传ID。
* @returns 返回上传ID的Promise对象
*/
generateUploadId() {
const { sourceFile: t, bucketName: s, fileDir: e } = this.uploadOptions;
return new Promise((u, R) => {
this.obsClient.initiateMultipartUpload(
{
Bucket: s,
Key: `${e}${t.name}`,
ContentType: t.type
},
(n, a) => {
n || a.CommonMsg.Status >= 300 ? R(h.create(o.SLICE_UPLOAD_INIT_ERROR)) : a.CommonMsg.Status < 300 && a.InterfaceResult ? u(a.InterfaceResult.UploadId) : R(h.create(o.SLICE_UPLOAD_INIT_ERROR));
}
);
});
}
/**
* 生成分片信息。
* @param fileSize 文件大小
* @param partSize 分片大小
* @returns 返回分片信息数组
*/
generateFileParts(t, s) {
const e = [];
let u = 0, R = 0;
for (; R < t; ) {
const n = Math.min(s, t - R), a = {
index: u + 1,
size: n,
offset: R
};
e.push(a), R += s, u += 1;
}
return e;
}
/**
* 上传各个分片。
* @param fileParts 分片信息数组
* @returns 返回上传结果的Promise对象数组
*/
async uploadFileParts(t) {
const { sourceFile: s, bucketName: e, fileDir: u } = this.uploadOptions, { uploadId: R } = this, n = [];
for (let a = 0; a < t.length; a += 1) {
const _ = t[a], E = await new Promise((P, A) => {
this.obsClient.uploadPart(
{
Bucket: e,
Key: `${u}${s.name}`,
UploadId: R,
SourceFile: s,
PartSize: _.size,
Offset: _.offset,
PartNumber: _.index
},
(c, I) => {
this.shouldAbort() || (c ? A(h.create(o.SLICE_UPLOAD_UPLOAD_ERROR)) : I.CommonMsg.Status < 300 && I.InterfaceResult ? P({
PartNumber: _.index,
ETag: I.InterfaceResult.ETag
}) : A(h.create(o.SLICE_UPLOAD_UPLOAD_ERROR)));
}
);
});
n.push(E);
}
return n;
}
/**
* 监听文件上传进度
*/
wathcUploadFileProgress() {
const { sourceFile: t, bucketName: s, fileDir: e } = this.uploadOptions;
this.obsClient.putObject({
Bucket: s,
Key: `${e}${t.name}`,
SourceFile: t,
ProgressCallback: (u, R) => {
var n, a;
this.shouldAbort() || (a = (n = this.uploadOptions) == null ? void 0 : n.onProgress) == null || a.call(n, {
percent: Math.max(
Math.min(99, Math.round(u / R * 100 || 0)),
1
)
});
}
});
}
/**
*
* @param parts 上传结果数组
* @returns 返回合并结果的Promise对象
*/
mergeFileParts(t) {
const { sourceFile: s, bucketName: e, fileDir: u } = this.uploadOptions, { uploadId: R } = this;
return new Promise((n, a) => {
this.obsClient.completeMultipartUpload(
{
Bucket: e,
Key: `${u}${s.name}`,
UploadId: R,
Parts: t
},
(_, E) => {
_ ? a(h.create(o.SLICE_UPLOAD_MERGE_ERROR)) : E.CommonMsg.Status < 300 && E.InterfaceResult ? n(E.InterfaceResult.Key) : a(h.create(o.SLICE_UPLOAD_MERGE_ERROR));
}
);
});
}
/**
* 中断分片上传。
* @returns 返回中断上传结果的Promise对象
*/
abort() {
const { sourceFile: t, bucketName: s, fileDir: e } = this.uploadOptions, { uploadId: u } = this;
return this.shouldUploading() ? new Promise((R, n) => {
this.obsClient.abortMultipartUpload(
{
Bucket: s,
Key: `${e}${t.name}`,
UploadId: u
},
(a, _) => {
var E, P;
a ? n(h.create(o.SLICE_UPLOAD_ABORT_ERROR)) : _.CommonMsg.Status < 300 ? (this.uploadStatus = S.ABORT, (P = (E = this.uploadOptions) == null ? void 0 : E.onAbort) == null || P.call(E), R(_)) : n(h.create(o.SLICE_UPLOAD_ABORT_ERROR));
}
);
}) : Promise.resolve();
}
shouldAbort() {
return this.uploadStatus === S.ABORT;
}
shouldUploading() {
return this.uploadStatus === S.UPLOADING;
}
}
class y {
/**
* 构造函数,初始化系统配置和文件上下文选项。
* @param systemConfig 系统配置
* @param fileContextOptions 文件上下文选项
*/
constructor(t, s) {
/**
* 系统配置
*/
i(this, "systemConfig");
i(this, "sourceFile");
this.systemConfig = t, this.sourceFile = s;
}
/**
* 创建OBS客户端实例。
* @returns 返回配置好的OBS客户端实例
* @private
*/
createObsClient() {
const { ACCESS_KEY_ID: t, SECRET_ACCESS_KEY: s, ENDPOINT: e } = this.systemConfig;
return new O({
access_key_id: t,
secret_access_key: s,
server: e,
timeout: 60 * 5
});
}
/**
* 获取当前日期作为文件目录。
*/
getFileDir() {
const t = /* @__PURE__ */ new Date(), s = t.getFullYear(), e = String(t.getMonth() + 1).padStart(2, "0"), u = String(t.getDate()).padStart(2, "0");
return `${s}/${e}/${u}/`;
}
/**
* 分片上传方法,使用SliceUpload类处理文件的分片上传。
* @returns 返回SliceUpload实例,用于执行分片上传流程
*/
createSliceUpload(t) {
const s = this.createObsClient();
return new T(s, {
sourceFile: this.sourceFile,
fileDir: this.getFileDir(),
bucketName: `${this.systemConfig.BUCKET_NAME}`,
...t,
onSuccess: (e) => {
var u;
(u = t == null ? void 0 : t.onSuccess) == null || u.call(t, e);
},
onProgress: (e) => {
var u;
(u = t == null ? void 0 : t.onProgress) == null || u.call(t, e);
},
onError: (e) => {
var u;
(u = t == null ? void 0 : t.onError) == null || u.call(t, e);
},
onAbort: () => {
var e;
(e = t == null ? void 0 : t.onAbort) == null || e.call(t);
},
onFinally: () => {
var e;
(e = t == null ? void 0 : t.onFinally) == null || e.call(t);
},
onStart: () => {
var e;
(e = t == null ? void 0 : t.onStart) == null || e.call(t);
}
});
}
}
let L = null;
const K = {
/**
* 设置系统和上传配置
* @param newConfig 包含系统配置的对象
*/
config(r) {
if (C(r.ENDPOINT) || C(r.ACCESS_KEY_ID) || C(r.SECRET_ACCESS_KEY) || C(r.BUCKET_NAME))
throw new Error("系统配置缺少必要的字段");
L = {
ENDPOINT: r.ENDPOINT,
ACCESS_KEY_ID: r.ACCESS_KEY_ID,
SECRET_ACCESS_KEY: r.SECRET_ACCESS_KEY,
BUCKET_NAME: r.BUCKET_NAME
// 使用正确的字段名
};
},
/**
* 创建文件上传上下文
* @param sourceFile 要上传的文件对象
* @returns 返回一个FileContext实例,用于管理文件上传
*/
createUploadContext(r) {
if (!L)
throw new Error("系统配置不能为空");
return new y(L, r);
}
};
export {
K as default
};