UNPKG

@mt-utils/huawei-obs

Version:

华为云OBS文件上传下载

324 lines (323 loc) 10.4 kB
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 };