UNPKG

js-uploader

Version:
402 lines 22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AwsS3TaskHandler = void 0; var tslib_1 = require("tslib"); var signature_v4_1 = require("@aws-sdk/signature-v4"); var sha256_js_1 = require("@aws-crypto/sha256-js"); var xml2js = require("xml2js"); var CommonsTaskHandler_1 = require("./CommonsTaskHandler"); var interface_1 = require("../../interface"); var rxjs_1 = require("rxjs"); var operators_1 = require("rxjs/operators"); var ajax_1 = require("rxjs/ajax"); var shared_1 = require("../../shared"); var SHA256_HEADER = 'x-amz-content-sha256'; var UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD'; var xml2jsParser = new xml2js.Parser(); var xml2jsBuilder = new xml2js.Builder(); var AwsS3TaskHandler = /** @class */ (function (_super) { tslib_1.__extends(AwsS3TaskHandler, _super); function AwsS3TaskHandler(task, uploaderOptions) { var _this = _super.call(this, task, uploaderOptions) || this; !AwsS3TaskHandler._overwrite && _this.processUploaderOptions(); return _this; } AwsS3TaskHandler.prototype.enable = function (task) { var ossOptions = this.uploaderOptions.ossOptions; return (ossOptions === null || ossOptions === void 0 ? void 0 : ossOptions.enable(task)) && ossOptions.provider === interface_1.OSSProvider.S3; }; AwsS3TaskHandler.prototype.abort = function () { this.abortTaskFiles(); _super.prototype.abort.call(this); return this; }; AwsS3TaskHandler.prototype.abortTaskFiles = function () { var _this = this; var sub = rxjs_1.of.apply(void 0, tslib_1.__spread(this.task.fileList)).pipe(operators_1.filter(function (file) { var _a = _this.getFileExtraInfo(file), key = _a.key, uploadId = _a.uploadId; return !!key && !!uploadId && file.status !== interface_1.StatusCode.Complete; }), operators_1.mergeMap(function (file) { var _a = _this.getFileExtraInfo(file), key = _a.key, uploadId = _a.uploadId; return _this.abortMultipartUpload(key, uploadId); }, 10)) .subscribe({ complete: function () { sub.unsubscribe(); sub = null; }, }); }; AwsS3TaskHandler.prototype.processUploaderOptions = function () { var _this = this; shared_1.Logger.info('🚀 ~ file: AwsS3TaskHandler.ts ~ line 42 ~ AwsS3TaskHandler ~ processUploaderOptions', this); var uploaderOptions = this.uploaderOptions; var ossOptions = uploaderOptions.ossOptions, beforeFileUploadComplete = uploaderOptions.beforeFileUploadComplete, beforeFileUploadStart = uploaderOptions.beforeFileUploadStart, beforeUploadResponseProcess = uploaderOptions.beforeUploadResponseProcess; if (!(ossOptions === null || ossOptions === void 0 ? void 0 : ossOptions.enable) || (ossOptions === null || ossOptions === void 0 ? void 0 : ossOptions.provider) !== interface_1.OSSProvider.S3) { throw new Error('ossOptions配置错误!'); } var chunkSize = uploaderOptions.chunkSize, chunked = uploaderOptions.chunked, requestBodyProcessFn = uploaderOptions.requestBodyProcessFn, requestOptions = uploaderOptions.requestOptions; var url = requestOptions.url, headers = requestOptions.headers, responseType = requestOptions.responseType, method = requestOptions.method; uploaderOptions.chunkSize = chunked ? Math.max(chunkSize || 0, Math.pow(1024, 2) * 5) : chunkSize; uploaderOptions.requestOptions.responseType = function (task, upfile, chunk) { if (!_this.enable(task)) { return typeof responseType === 'function' ? responseType(task, upfile, chunk) : responseType; } else { return 'text'; } }; uploaderOptions.requestOptions.method = function (task, upfile, chunk) { if (!_this.enable(task)) { return typeof method === 'function' ? method(task, upfile, chunk) : method; } else { return 'PUT'; } }; uploaderOptions.requestOptions.url = function (task, upfile, chunk) { if (!_this.enable(task)) { return _this.createObserverble(url, task, upfile, chunk).toPromise(); } return _this.getRequestBaseURL() .pipe(operators_1.map(function (baseURL) { var _a = _this.getFileExtraInfo(upfile), key = _a.key, uploadId = _a.uploadId; return baseURL + "/" + key + "?partNumber=" + (chunk.index + 1) + "&uploadId=" + uploadId; })) .toPromise(); }; uploaderOptions.requestOptions.headers = function (task, upfile, chunk) { if (!_this.enable(task)) { return _this.createObserverble(headers, task, upfile, chunk).toPromise(); } return _this.getRequestBaseURL() .pipe(operators_1.map(function (baseURL) { var _a; var _b = _this.getFileExtraInfo(upfile), key = _b.key, uploadId = _b.uploadId; return { url: baseURL + "/" + key, method: uploaderOptions.requestOptions.method, headers: (_a = {}, _a[SHA256_HEADER] = UNSIGNED_PAYLOAD, _a), query: { partNumber: String(chunk.index + 1), uploadId: uploadId }, }; }), operators_1.switchMap(function (requestToSign) { return _this.signRequest(requestToSign); }), operators_1.map(function (_a) { var headers = _a.headers; return tslib_1.__assign({ 'Content-Type': 'application/octet-stream; charset=UTF-8' }, headers); })) .toPromise(); }; uploaderOptions.requestBodyProcessFn = function (task, upfile, chunk, params) { if (_this.enable(task)) { return params.file; } else { return requestBodyProcessFn === null || requestBodyProcessFn === void 0 ? void 0 : requestBodyProcessFn(task, upfile, chunk, params); } }; var overwriteFns = this.getOverwriteFns(); if ((beforeFileUploadComplete === null || beforeFileUploadComplete === void 0 ? void 0 : beforeFileUploadComplete.name) !== overwriteFns.overwriteBeforeFileUploadComplete.name) { uploaderOptions.beforeFileUploadComplete = overwriteFns.overwriteBeforeFileUploadComplete; } if ((beforeFileUploadStart === null || beforeFileUploadStart === void 0 ? void 0 : beforeFileUploadStart.name) !== overwriteFns.overwriteBeforeFileUploadStart.name) { uploaderOptions.beforeFileUploadStart = overwriteFns.overwriteBeforeFileUploadStart; } if ((beforeUploadResponseProcess === null || beforeUploadResponseProcess === void 0 ? void 0 : beforeUploadResponseProcess.name) !== overwriteFns.overwriteBeforeUploadResponseProcess.name) { uploaderOptions.beforeUploadResponseProcess = overwriteFns.overwriteBeforeUploadResponseProcess; } AwsS3TaskHandler._overwrite = true; }; AwsS3TaskHandler.prototype.getOverwriteFns = function () { var _this = this; var uploaderOptions = this.uploaderOptions; var beforeFileUploadComplete = uploaderOptions.beforeFileUploadComplete, beforeFileUploadStart = uploaderOptions.beforeFileUploadStart, beforeUploadResponseProcess = uploaderOptions.beforeUploadResponseProcess; return { overwriteBeforeFileUploadStart: function (task, upFile) { var extraInfo = _this.getFileExtraInfo(upFile); var beforeUpload = function () { return (beforeFileUploadStart === null || beforeFileUploadStart === void 0 ? void 0 : beforeFileUploadStart(task, upFile)) || Promise.resolve(); }; if (!_this.enable(task)) { return beforeUpload(); } var getObjectKey = function () { var _a, _b; var objectKey = ((_b = (_a = uploaderOptions.ossOptions) === null || _a === void 0 ? void 0 : _a.keyGenerator) === null || _b === void 0 ? void 0 : _b.call(_a, upFile, task)) || Promise.resolve(''); return _this.toObserverble(objectKey).pipe(operators_1.map(function (key) { return (extraInfo.key = key); })); }; var createMultipartUpload = function () { if (extraInfo.uploadId) { return rxjs_1.of(extraInfo); } return getObjectKey().pipe(operators_1.switchMap(function (key) { return _this.createMultipartUpload(key); }), operators_1.tap(function (_a) { var uploadId = _a.uploadId, bucket = _a.bucket; return Object.assign(extraInfo, { uploadId: uploadId, bucket: bucket }); })); }; return rxjs_1.of(null).pipe(operators_1.concatMap(createMultipartUpload), operators_1.concatMap(beforeUpload)).toPromise(); }, overwriteBeforeFileUploadComplete: function (task, file) { var beforeFileComplete = function () { return (beforeFileUploadComplete === null || beforeFileUploadComplete === void 0 ? void 0 : beforeFileUploadComplete(task, file)) || Promise.resolve(); }; if (!_this.enable(task)) { return beforeFileComplete(); } var completeMultipartUpload = function () { if (file.response.etag) { return rxjs_1.of(file.response); } return new rxjs_1.Observable(function (subscriber) { var _a; var _b = _this.getFileExtraInfo(file), key = _b.key, uploadId = _b.uploadId; var parts = (_a = file.chunkList) === null || _a === void 0 ? void 0 : _a.map(function (ck) { return ({ ETag: ck.response.etag, PartNumber: ck.index + 1, }); }); _this.completeMultipartUpload(key, uploadId, parts) .pipe(operators_1.tap(function (res) { file.response = res; })) .subscribe(subscriber); }); }; return rxjs_1.of(null).pipe(operators_1.concatMap(completeMultipartUpload), operators_1.concatMap(beforeFileComplete)).toPromise(); }, overwriteBeforeUploadResponseProcess: function (task, file, chunk, response) { var _a; if (!_this.enable(task)) { return Promise.resolve(); } var etag = ((_a = response.xhr.getResponseHeader('etag')) === null || _a === void 0 ? void 0 : _a.replace(/['"]/g, '')) || ''; response.response = { etag: etag }; return (beforeUploadResponseProcess === null || beforeUploadResponseProcess === void 0 ? void 0 : beforeUploadResponseProcess(task, file, chunk, response)) || Promise.resolve(); }, }; }; AwsS3TaskHandler.prototype.createMultipartUpload = function (key) { var _this = this; var job = function (baseURL) { var requestToSign = { url: baseURL + "/" + key + "?uploads", method: 'POST', query: { uploads: '' }, }; return rxjs_1.from(_this.signRequest(requestToSign)).pipe(operators_1.switchMap(function (_a) { var method = _a.method, body = _a.body, headers = _a.headers; return ajax_1.ajax({ url: requestToSign.url, method: method, body: body, headers: headers, responseType: 'text', }).pipe(operators_1.switchMap(function (res) { return rxjs_1.from(xml2jsParser.parseStringPromise(res.response)); }), operators_1.map(function (res) { var _a = res === null || res === void 0 ? void 0 : res.InitiateMultipartUploadResult, Bucket = _a.Bucket, Key = _a.Key, UploadId = _a.UploadId; return { bucket: Bucket[0], key: Key[0], uploadId: UploadId[0] }; })); })); }; return this.getRequestBaseURL().pipe(operators_1.switchMap(job)); }; AwsS3TaskHandler.prototype.uploadPart = function (key, partNumber, uploadId, body) { var _this = this; var job = function (baseURL) { var _a; var requestToSign = { url: baseURL + "/" + key, method: 'PUT', headers: (_a = {}, _a[SHA256_HEADER] = UNSIGNED_PAYLOAD, _a), query: { partNumber: String(partNumber), uploadId: uploadId }, body: body, }; return rxjs_1.from(_this.signRequest(requestToSign)).pipe(operators_1.switchMap(function (_a) { var query = _a.query, method = _a.method, body = _a.body, headers = _a.headers; var queryString = _this.stringifyQuery(query); var url = queryString ? requestToSign.url + '?' + queryString : requestToSign.url; return ajax_1.ajax({ url: url, method: method, body: body, headers: tslib_1.__assign({ 'Content-Type': 'application/octet-stream; charset=UTF-8' }, headers), responseType: 'text', }).pipe(operators_1.map(function (res) { var _a; var etag = ((_a = res.xhr.getResponseHeader('etag')) === null || _a === void 0 ? void 0 : _a.replace(/['"]/g, '')) || ''; return { uploadId: uploadId, key: key, partNumber: partNumber, etag: etag }; })); })); }; return this.getRequestBaseURL().pipe(operators_1.switchMap(job)); }; AwsS3TaskHandler.prototype.completeMultipartUpload = function (key, uploadId, parts) { var _this = this; var job = function (baseURL) { var _a; var requestToSign = { url: baseURL + "/" + key, method: 'POST', query: { uploadId: uploadId }, headers: (_a = {}, _a[SHA256_HEADER] = UNSIGNED_PAYLOAD, _a), body: xml2jsBuilder.buildObject({ CompleteMultipartUpload: { $: { xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/', }, Part: parts.sort(function (a, b) { return a.PartNumber - b.PartNumber; }), }, }), }; return rxjs_1.from(_this.signRequest(requestToSign)).pipe(operators_1.switchMap(function (_a) { var method = _a.method, body = _a.body, headers = _a.headers, query = _a.query; var queryString = _this.stringifyQuery(query); var url = queryString ? requestToSign.url + '?' + queryString : requestToSign.url; return ajax_1.ajax({ url: url, method: method, body: body, headers: tslib_1.__assign({ 'Content-Type': 'application/octet-stream; charset=UTF-8' }, headers), responseType: 'text', }).pipe(operators_1.switchMap(function (res) { return rxjs_1.from(xml2jsParser.parseStringPromise(res.response)); }), operators_1.map(function (res) { var _a = res.CompleteMultipartUploadResult || {}, Bucket = _a.Bucket, ETag = _a.ETag, Key = _a.Key; return { uploadId: uploadId, bucket: Bucket[0], etag: ETag[0], key: Key[0], }; })); })); }; return this.getRequestBaseURL().pipe(operators_1.switchMap(job)); }; AwsS3TaskHandler.prototype.abortMultipartUpload = function (key, uploadId) { var _this = this; var job = function (baseURL) { var _a; var requestToSign = { url: baseURL + "/" + key, method: 'DELETE', query: { uploadId: uploadId }, headers: (_a = {}, _a[SHA256_HEADER] = UNSIGNED_PAYLOAD, _a), }; return rxjs_1.from(_this.signRequest(requestToSign)).pipe(operators_1.switchMap(function (_a) { var method = _a.method, headers = _a.headers, query = _a.query; var queryString = _this.stringifyQuery(query); var url = queryString ? requestToSign.url + '?' + queryString : requestToSign.url; return ajax_1.ajax({ url: url, method: method, headers: headers, responseType: 'text', }).pipe(operators_1.mapTo(true), operators_1.catchError(function () { return rxjs_1.of(false); })); })); }; return this.getRequestBaseURL().pipe(operators_1.switchMap(job)); }; AwsS3TaskHandler.prototype.signRequest = function (requestToSign, signatureV4) { return tslib_1.__awaiter(this, void 0, void 0, function () { var url, method, query, headers, body, _a, pathname, hostname, host, protocol, origin, _b, signed; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: shared_1.Logger.info('🚀 ~ file: AwsS3TaskHandler.ts ~ line 324 ~ AwsS3TaskHandler ~ signRequest ~ requestToSign', requestToSign); url = requestToSign.url, method = requestToSign.method, query = requestToSign.query, headers = requestToSign.headers, body = requestToSign.body; _a = new URL(url), pathname = _a.pathname, hostname = _a.hostname, host = _a.host, protocol = _a.protocol, origin = _a.origin; headers = Object.assign(headers || {}, { host: host }); url = origin + pathname; if (!(signatureV4 !== null && signatureV4 !== void 0)) return [3 /*break*/, 1]; _b = signatureV4; return [3 /*break*/, 3]; case 1: return [4 /*yield*/, this.getRequestSigner().toPromise()]; case 2: _b = (_c.sent()); _c.label = 3; case 3: signatureV4 = _b; return [4 /*yield*/, signatureV4.sign({ method: method, headers: headers, query: query, path: pathname, hostname: hostname, protocol: protocol, body: body, })]; case 4: signed = _c.sent(); shared_1.Logger.info('🚀 ~ file: AwsS3TaskHandler.ts ~ line 79 ~ AwsS3TaskHandler ~ signRequest ~ signed', signed); delete signed.headers.host; return [2 /*return*/, signed]; } }); }); }; AwsS3TaskHandler.prototype.stringifyQuery = function (params) { if (params === void 0) { params = {}; } return Object.keys(params) .map(function (k) { return k + "=" + params[k]; }) .join('&'); }; AwsS3TaskHandler.prototype.getS3Config = function () { var _this = this; if (this.s3Config) { return rxjs_1.of(this.s3Config); } var ossOptions = this.uploaderOptions.ossOptions; return this.createObserverble(ossOptions.s3Config).pipe(operators_1.tap(function (s3config) { _this.s3Config = s3config; })); }; AwsS3TaskHandler.prototype.getRequestBaseURL = function () { var _this = this; if (this.requestBaseURL && /^https?:\/\//.test(this.requestBaseURL)) { return rxjs_1.of(this.requestBaseURL); } return this.getS3Config().pipe(operators_1.map(function (s3Config) { var endpoint = s3Config.endpoint; return (_this.requestBaseURL = (endpoint === null || endpoint === void 0 ? void 0 : endpoint.protocol) + "//" + (endpoint === null || endpoint === void 0 ? void 0 : endpoint.hostname)); })); }; AwsS3TaskHandler.prototype.getRequestSigner = function () { var _this = this; if (this.requestSigner) { return rxjs_1.of(this.requestSigner); } return this.getS3Config().pipe(operators_1.map(function (s3Config) { var _a = s3Config, region = _a.region, credentials = _a.credentials; return (_this.requestSigner = new signature_v4_1.SignatureV4({ service: 's3', credentials: credentials, region: region, sha256: sha256_js_1.Sha256, uriEscapePath: false, })); })); }; AwsS3TaskHandler.prototype.getFileExtraInfo = function (file) { file.extraInfo = file.extraInfo || {}; return file.extraInfo; }; AwsS3TaskHandler._overwrite = false; return AwsS3TaskHandler; }(CommonsTaskHandler_1.CommonsTaskHandler)); exports.AwsS3TaskHandler = AwsS3TaskHandler; //# sourceMappingURL=AwsS3TaskHandler.js.map