UNPKG

js-uploader

Version:
695 lines 39.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CommonsTaskHandler = void 0; var tslib_1 = require("tslib"); var TaskHandler_1 = require("./TaskHandler"); var interface_1 = require("../../interface"); var rxjs_1 = require("rxjs"); var operators_1 = require("rxjs/operators"); var ajax_1 = require("rxjs/ajax"); var operators_2 = require("../../operators"); var assert_1 = require("../../utils/assert"); var helpers_1 = require("../helpers"); var utils_1 = require("../../utils"); var shared_1 = require("../../shared"); var SubjectAction; (function (SubjectAction) { SubjectAction["AbortFile"] = "abort-file"; SubjectAction["PauseFile"] = "pause-file"; })(SubjectAction || (SubjectAction = {})); var CommonsTaskHandler = /** @class */ (function (_super) { tslib_1.__extends(CommonsTaskHandler, _super); function CommonsTaskHandler() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.progressSubject = new rxjs_1.Subject(); _this.upload$ = null; _this.subscription = null; _this.subject = new rxjs_1.BehaviorSubject({}); _this.uploadFileIDSubject = new rxjs_1.Subject(); _this.fileSubscriptionMap = new Map(); _this.fileSubscriptionInfoMap = new Map(); return _this; } CommonsTaskHandler.prototype.pause = function () { var _this = this; var _a; (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this.subscription = null; var task = this.task; task.status = task.status === interface_1.StatusCode.Complete ? task.status : interface_1.StatusCode.Pause; this.isResumable() && this.presistTaskOnly(this.task); rxjs_1.scheduled(task.fileList || [], rxjs_1.asyncScheduler) .pipe(operators_1.tap(function (file) { var status = file.status === interface_1.StatusCode.Complete || file.status === interface_1.StatusCode.Error ? file.status : interface_1.StatusCode.Pause; _this.changeUploadFileStatus(file, status); _this.emit(interface_1.EventType.FilePause, task, file); _this.isResumable() && _this.presistFileOnly(file); })) .subscribe(); this.emit(interface_1.EventType.TaskPause, this.task); return this; }; CommonsTaskHandler.prototype.resume = function () { this.handle().emit(interface_1.EventType.TaskResume, this.task); return this; }; CommonsTaskHandler.prototype.retry = function () { var _this = this; var _a; var errorFiles = ((_a = this.task.fileList) === null || _a === void 0 ? void 0 : _a.filter(function (i) { return i.status === interface_1.StatusCode.Error; })) || []; rxjs_1.scheduled(errorFiles, rxjs_1.asyncScheduler).subscribe({ next: function (file) { _this.changeUploadFileStatus(file, interface_1.StatusCode.Pause); _this.emit(interface_1.EventType.FilePause, _this.task, file); }, complete: function () { _this.handle().emit(interface_1.EventType.TaskRetry, _this.task); }, }); return this; }; CommonsTaskHandler.prototype.abort = function () { var _a; this.upload$ = this.subscription = (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this.emit(interface_1.EventType.TaskCancel, this.task); return this; }; CommonsTaskHandler.prototype.pauseFile = function () { var _this = this; var files = []; for (var _i = 0; _i < arguments.length; _i++) { files[_i] = arguments[_i]; } var rawFiles = []; rxjs_1.scheduled(files, rxjs_1.asyncScheduler) .pipe(operators_1.bufferCount(100), operators_1.concatMap(function (files) { return rxjs_1.from(files).pipe(operators_1.tap(function (file) { var _a; (_a = _this.fileSubscriptionMap.get(file.id)) === null || _a === void 0 ? void 0 : _a.unsubscribe(); var rawFile = _this.task.fileList.find(function (i) { return i.id === file.id; }); if (rawFile && rawFile.status !== interface_1.StatusCode.Complete && rawFile.status !== interface_1.StatusCode.Error) { _this.changeUploadFileStatus(rawFile, interface_1.StatusCode.Pause); _this.emit(interface_1.EventType.FilePause, _this.task, rawFile); rawFiles.push(rawFile); } })); })) .subscribe({ complete: function () { _this.emit(interface_1.EventType.FilesPause, _this.task, rawFiles); }, }); return this; }; CommonsTaskHandler.prototype.abortFile = function () { var _this = this; var files = []; for (var _i = 0; _i < arguments.length; _i++) { files[_i] = arguments[_i]; } rxjs_1.scheduled(files, rxjs_1.asyncScheduler) .pipe(operators_1.bufferCount(100), operators_1.concatMap(function (files) { return rxjs_1.from(files).pipe(operators_1.tap(function (file) { var _a; var subscriber = _this.fileSubscriptionInfoMap.get(file.id); subscriber === null || subscriber === void 0 ? void 0 : subscriber.complete(); subscriber === null || subscriber === void 0 ? void 0 : subscriber.unsubscribe(); var idIndex = _this.task.fileIDList.indexOf(file.id); if (idIndex > -1) { _this.task.fileIDList.splice(idIndex, 1); _this.task.fileSize -= file.size; _this.task.uploaded -= file.uploaded; } var fileIndex = (_a = _this.task.fileList) === null || _a === void 0 ? void 0 : _a.findIndex(function (i) { return i.id === file.id; }); if (fileIndex > -1) { _this.changeUploadFileStatus(_this.task.fileList[fileIndex], interface_1.StatusCode.Pause); _this.task.fileList.splice(fileIndex, 1); } _this.emit(interface_1.EventType.FileCancel, _this.task, file); _this.emit(interface_1.EventType.TaskUpdate, _this.task); })); })) .subscribe({ complete: function () { _this.emit(interface_1.EventType.FilesCancel, _this.task, files); }, }); return this; }; CommonsTaskHandler.prototype.handle = function () { var _this = this; var _a; shared_1.Logger.info('CommonTaskHandler -> handle -> task', this.task); if (!this.upload$) { this.upload$ = rxjs_1.of(this.task).pipe(operators_1.switchMap(function (task) { var _a, _b; // 任务开始前hook var beforeTaskStart = _this.hookWrap((_b = (_a = _this.uploaderOptions).beforeTaskStart) === null || _b === void 0 ? void 0 : _b.call(_a, task)); return rxjs_1.from(beforeTaskStart).pipe(operators_1.mapTo(task)); }), operators_1.tap(function (task) { shared_1.Logger.info('🚀 ~ 开始上传', task); _this.changeUplotaTaskStatus(task, interface_1.StatusCode.Uploading); _this.emit(interface_1.EventType.TaskUploadStart, task); }), operators_1.switchMap(function () { return _this.createUploadJob(); })); } (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this.subscription = this.upload$.subscribe({ next: function () { shared_1.Logger.info('🚀 ~ 上传任务 next '); }, error: function (err) { shared_1.Logger.info('🚀 ~ 上传任务出错', err); _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Error); _this.emit(interface_1.EventType.TaskError, _this.task, err); }, complete: function () { shared_1.Logger.info('🚀 ~ 上传任务完成', _this.task); if (_this.task.fileList.every(function (i) { return i.status === interface_1.StatusCode.Complete; })) { _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Complete); _this.emit(interface_1.EventType.TaskComplete, _this.task); // this.removeTaskFromStroage(this.task) } else if (_this.task.fileList.some(function (i) { return i.status === interface_1.StatusCode.Error; })) { _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Error); _this.emit(interface_1.EventType.TaskError, _this.task); } else if (_this.task.fileList.some(function (i) { return i.status === interface_1.StatusCode.Pause; })) { _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Pause); _this.emit(interface_1.EventType.TaskPause, _this.task); } _this.uploaderOptions.resumable && _this.presistTaskOnly(_this.task); rxjs_1.from(_this.fileSubscriptionInfoMap.values()).subscribe(function (subscriber) { return subscriber.unsubscribe(); }); }, }); this.subscription.add(this.handleProgress().subscribe()); return this; }; CommonsTaskHandler.prototype.handle1 = function (uploadFiles) { var _this = this; var _a; if (!this.upload$) { this.upload$ = rxjs_1.of(this.task).pipe(operators_1.switchMap(function (task) { var _a, _b; // 任务开始前hook var beforeTaskStart = _this.hookWrap((_b = (_a = _this.uploaderOptions).beforeTaskStart) === null || _b === void 0 ? void 0 : _b.call(_a, task)); return rxjs_1.from(beforeTaskStart).pipe(operators_1.mapTo(task)); }), operators_1.tap(function (task) { shared_1.Logger.info('🚀 ~ 开始上传', task); _this.changeUplotaTaskStatus(task, interface_1.StatusCode.Uploading); _this.emit(interface_1.EventType.TaskUploadStart, task); }), operators_1.switchMap(function () { return _this.uploadFileIDSubject.pipe(operators_1.mergeMap(function (id) { return _this.executeForResult(id); }, 2), operators_1.tap(function () { }), operators_1.takeWhile(function () { return !_this.task.fileIDList.every(function (id) { var _a; return (_a = _this.fileSubscriptionMap.get(id)) === null || _a === void 0 ? void 0 : _a.closed; }); })); })); } (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe(); this.subscription = this.upload$.subscribe({ next: function () { shared_1.Logger.info('🚀 ~ 上传任务 next '); }, error: function (err) { shared_1.Logger.info('🚀 ~ 上传任务出错', err); _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Error); _this.emit(interface_1.EventType.TaskError, _this.task, err); }, complete: function () { shared_1.Logger.info('🚀 ~ 上传任务完成', _this.task); if (_this.task.fileList.every(function (i) { return i.status === interface_1.StatusCode.Complete; })) { _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Complete); _this.emit(interface_1.EventType.TaskComplete, _this.task); _this.removeTaskFromStroage(_this.task); } else if (_this.task.fileList.some(function (i) { return i.status === interface_1.StatusCode.Pause || i.status === interface_1.StatusCode.Error; })) { _this.changeUplotaTaskStatus(_this.task, interface_1.StatusCode.Pause); _this.emit(interface_1.EventType.TaskPause, _this.task); } }, }); this.subscription.add(this.handleProgress().subscribe()); if (uploadFiles === null || uploadFiles === void 0 ? void 0 : uploadFiles.length) { rxjs_1.scheduled(uploadFiles, rxjs_1.asyncScheduler).subscribe(function (file) { return _this.putNextFile(file); }); } else { this.putNextFile(); } return this; }; CommonsTaskHandler.prototype.executeForResult = function (fileID) { var _this = this; return rxjs_1.of(fileID).pipe(operators_1.concatMap(function (id) { return new Promise(function (resolve, reject) { var _a; (_a = _this.fileSubscriptionMap.get(id)) === null || _a === void 0 ? void 0 : _a.unsubscribe(); var subscription = new rxjs_1.Observable(function (subscriber) { var subscription = _this.createFileUploadJob(id).subscribe(subscriber); return function () { subscription.unsubscribe(); resolve(); }; }).subscribe({ complete: function () { return resolve(); }, error: function (e) { return reject(e); }, }); _this.fileSubscriptionMap.set(id, subscription); }); })); }; CommonsTaskHandler.prototype.putNextFile = function (uploadFile) { var _this = this; if (uploadFile) { if (typeof uploadFile === 'object') { this.uploadFileIDSubject.next(uploadFile.id); } else { this.uploadFileIDSubject.next(uploadFile); } } else { rxjs_1.scheduled(this.task.fileIDList, rxjs_1.asyncScheduler).subscribe(function (id) { return _this.uploadFileIDSubject.next(id); }); } }; CommonsTaskHandler.prototype.createFileUploadJob = function (fileID) { var _this = this; var pocessed = []; return rxjs_1.of(fileID).pipe(operators_1.filter(function (id) { var _a; var _b = _this.subject.getValue(), action = _b.action, data = _b.data; var accept = !((action === SubjectAction.AbortFile || action === SubjectAction.PauseFile) && ((_a = data) === null || _a === void 0 ? void 0 : _a.includes(id))); !accept && pocessed.push(id); return accept; }), operators_1.concatMap(function (fileID) { // 根据ID获取文件 return _this.getUploadFileByID(fileID).pipe(operators_1.map(function (uploadFile) { assert_1.assert(!!uploadFile, 'file not found! ID:' + fileID); return _this.putToTaskFileList(uploadFile); })); }), operators_1.filter(function (uploadFile) { // 过滤完成的文件 var isComplete = uploadFile.status === interface_1.StatusCode.Complete; if (isComplete) { pocessed.push(uploadFile.id); shared_1.Logger.warn("skip file,status:" + uploadFile.status, uploadFile.name); } return !isComplete; }), // filter((uploadFile: UploadFile) => { // // 根据配置 跳过出错的文件 // const skip: boolean = uploadFile.status === StatusCode.Error && !!this.uploaderOptions.skipFileWhenUploadError // if (skip) { // pocessed.push(uploadFile.id) // Logger.warn(`skip file,status:${uploadFile.status}`, uploadFile.name) // } // return !skip // }), operators_1.tap(function (uploadFile) { _this.changeUploadFileStatus(uploadFile, interface_1.StatusCode.Waiting); _this.emit(interface_1.EventType.FileWaiting, _this.task, uploadFile); }), operators_1.concatMap(function (uploadFile) { var ob$ = _this.uploadFile(uploadFile).pipe(operators_1.tap(function () { pocessed.push(uploadFile.id); })); return ob$; })); }; CommonsTaskHandler.prototype.createUploadJob = function () { var _this = this; return rxjs_1.scheduled(this.task.fileIDList || [], rxjs_1.asyncScheduler).pipe(operators_1.filter(function (id) { var _a; var _b = _this.subject.getValue(), action = _b.action, data = _b.data; return !((action === SubjectAction.AbortFile || action === SubjectAction.PauseFile) && ((_a = data) === null || _a === void 0 ? void 0 : _a.includes(id))); }), operators_1.concatMap(function (fileID) { // 根据ID获取文件 return _this.getUploadFileByID(fileID).pipe(operators_1.map(function (uploadFile) { assert_1.assert(!!uploadFile, 'file not found! ID:' + fileID); return _this.putToTaskFileList(uploadFile); })); }), operators_1.filter(function (uploadFile) { // 过滤完成的文件 var isComplete = uploadFile.status === interface_1.StatusCode.Complete; if (isComplete) { shared_1.Logger.warn("skip file,status:" + uploadFile.status, uploadFile.name); } return !isComplete; }), // filter((uploadFile: UploadFile) => { // // 根据配置 跳过出错的文件 // const skip: boolean = uploadFile.status === StatusCode.Error && !!this.uploaderOptions.skipFileWhenUploadError // if (skip) { // Logger.warn(`skip file,status:${uploadFile.status}`, uploadFile.name) // } // return !skip // }), operators_1.tap(function (uploadFile) { _this.changeUploadFileStatus(uploadFile, interface_1.StatusCode.Waiting); _this.emit(interface_1.EventType.FileWaiting, _this.task, uploadFile); }), operators_1.mergeMap(function (uploadFile) { var subscriber = _this.fileSubscriptionInfoMap.get(uploadFile.id); subscriber === null || subscriber === void 0 ? void 0 : subscriber.complete(); subscriber === null || subscriber === void 0 ? void 0 : subscriber.unsubscribe(); return new rxjs_1.Observable(function (subscriber) { var subscription = _this.uploadFile(uploadFile).subscribe(subscriber); _this.fileSubscriptionInfoMap.set(uploadFile.id, subscriber); return function () { return subscription.unsubscribe(); }; }); }, this.uploaderOptions.fileConcurrency || 1)); }; CommonsTaskHandler.prototype.uploadFile = function (uploadFile) { var _this = this; var _a = this, task = _a.task, uploaderOptions = _a.uploaderOptions; return rxjs_1.of(uploadFile).pipe(operators_1.concatMap(function (uploadFile) { _this.changeUploadFileStatus(uploadFile, interface_1.StatusCode.Uploading); // 判断是否需要计算hash/md5 var should = !!uploaderOptions.computeFileHash && !uploadFile.hash; if (!should) { shared_1.Logger.info('should not compute hash for', uploadFile.name); return rxjs_1.of(uploadFile); } // hash计算前后hook var _a = _this.uploaderOptions, beforeFileHashCompute = _a.beforeFileHashCompute, fileHashComputed = _a.fileHashComputed; var beforeCompute = _this.hookWrap(beforeFileHashCompute === null || beforeFileHashCompute === void 0 ? void 0 : beforeFileHashCompute(task, uploadFile)); return rxjs_1.from(beforeCompute).pipe(operators_1.concatMap(function () { // 使用线程池计算hash return _this.computeFileMd5ByWorker(uploadFile).pipe(operators_1.map(function (hash) { return Object.assign(uploadFile, { hash: hash }); })); }), operators_1.concatMap(function (uploadFile) { // hash计算后 var computed = _this.hookWrap(fileHashComputed === null || fileHashComputed === void 0 ? void 0 : fileHashComputed(task, uploadFile, uploadFile.hash)); return rxjs_1.from(computed).pipe(operators_1.mapTo(uploadFile)); })); }), operators_1.concatMap(function (uploadFile) { var _a; // 文件上传开始前hook var beforeFileUploadStart = _this.hookWrap((_a = uploaderOptions.beforeFileUploadStart) === null || _a === void 0 ? void 0 : _a.call(uploaderOptions, task, uploadFile)); return rxjs_1.from(beforeFileUploadStart).pipe(operators_1.mapTo(uploadFile)); }), operators_1.filter(function (uploadFile) { return uploadFile.status !== interface_1.StatusCode.Complete && uploadFile.status !== interface_1.StatusCode.Pause; }), // 再次过滤成功的文件 operators_1.concatMap(function (uploadFile) { // 判断是否需要计算分片 var chunkIDList = uploadFile.chunkIDList, chunkList = uploadFile.chunkList; var should = !(chunkList === null || chunkList === void 0 ? void 0 : chunkList.length) || chunkList.length !== (chunkIDList === null || chunkIDList === void 0 ? void 0 : chunkIDList.length); if (!should) { return rxjs_1.of(uploadFile); } // 计算分片,仅计算切片索引不切割文件 var maxChunkCount = 10000; var chunked = !!uploaderOptions.chunked; var chunkSize = chunked ? uploaderOptions.chunkSize || Math.pow(1024, 2) * 4 : Number.MAX_SAFE_INTEGER; if (Math.ceil(uploadFile.size / chunkSize) > maxChunkCount) { chunkSize = Math.ceil(chunkSize / maxChunkCount); } return _this.generateFileChunks(chunkSize, uploadFile).pipe(operators_1.concatMap(function (chunkList) { var chunkIDList = chunkList.map(function (ck) { return ck.id; }); Object.assign(uploadFile, { chunkList: chunkList, chunkIDList: chunkIDList }); // 保存分片和文件信息 if (_this.isResumable()) { return rxjs_1.forkJoin([rxjs_1.from(_this.presistChunkOnly.apply(_this, tslib_1.__spread(chunkList))), rxjs_1.from(_this.presistFileOnly(uploadFile))]); } else { return rxjs_1.of(''); } }), operators_1.mapTo(uploadFile)); }), operators_1.concatMap(function (uploadFile) { // 文件上传事件 _this.emit(interface_1.EventType.FileUploadStart, _this.task, uploadFile); var concurrency = uploaderOptions.chunkConcurrency || 1; // 上传所有分片并控制并发 return _this.uploadChunks(uploadFile, concurrency).pipe(operators_1.map(function (chunkResponses) { return ({ uploadFile: uploadFile, chunkResponses: chunkResponses }); })); }), operators_1.concatMap(function (res) { var _a; // 文件上传完成前hook var beforeComplete = _this.hookWrap((_a = uploaderOptions.beforeFileUploadComplete) === null || _a === void 0 ? void 0 : _a.call(uploaderOptions, task, uploadFile)); return rxjs_1.from(beforeComplete).pipe(operators_1.mapTo(res)); }), operators_1.catchError(function (e) { shared_1.Logger.info('🚀 ~ upload error', uploadFile, e); // 文件上传错误事件 _this.changeUploadFileStatus(uploadFile, interface_1.StatusCode.Error); _this.emit(interface_1.EventType.FileError, _this.task, uploadFile, e); _this.presistFileOnly(uploadFile); // 错误处理 判断是否需要过滤该文件 if (!uploaderOptions.skipFileWhenUploadError) { return rxjs_1.throwError(e); } else { return rxjs_1.of({ uploadFile: uploadFile, chunkResponses: [] }); } }), operators_1.tap(function (_a) { var _b, _c; var uploadFile = _a.uploadFile, chunkResponses = _a.chunkResponses; shared_1.Logger.info('🚀 ~ upload complete', uploadFile, chunkResponses); // 文件上传完成事件 uploadFile.response = !uploadFile.response && (chunkResponses === null || chunkResponses === void 0 ? void 0 : chunkResponses.length) ? (_c = (_b = chunkResponses[chunkResponses.length - 1]) === null || _b === void 0 ? void 0 : _b.response) === null || _c === void 0 ? void 0 : _c.response : uploadFile.response; if (uploadFile.status !== interface_1.StatusCode.Error) { _this.changeUploadFileStatus(uploadFile, interface_1.StatusCode.Complete); _this.emit(interface_1.EventType.FileComplete, _this.task, uploadFile, chunkResponses); } _this.presistFileOnly(uploadFile); }), operators_1.takeUntil(this.subject.pipe(operators_1.filter(function (i) { var _a; return (i.action === SubjectAction.AbortFile || i.action === SubjectAction.PauseFile) && ((_a = i.data) === null || _a === void 0 ? void 0 : _a.includes(uploadFile.id)); }), operators_1.tap(function () { return _this.changeUploadFileStatus(uploadFile, interface_1.StatusCode.Pause); })))); }; CommonsTaskHandler.prototype.uploadChunks = function (uploadFile, concurrency) { var _this = this; var chunkList = uploadFile.chunkList || []; var baseParams = { fileID: uploadFile.id, fileHash: uploadFile.hash || '', fileName: uploadFile.name, fileSize: uploadFile.size, relativePath: uploadFile.relativePath, chunkSize: this.uploaderOptions.chunkSize, chunkCount: chunkList.length, chunkIndex: 0, currentChunkSize: 0, }; return rxjs_1.scheduled(chunkList || [], rxjs_1.asyncScheduler).pipe(operators_1.filter(function (chunk) { // 过滤完成的分片 var isComplete = chunk.status === interface_1.StatusCode.Complete; if (isComplete) { shared_1.Logger.info("skip chunk\uFF0Cstatus:" + chunk.status, uploadFile.name, chunk); } return !isComplete; }), operators_1.tap(function (chunk) { _this.changeFileChunkStatus(chunk, interface_1.StatusCode.Waiting); }), operators_1.mergeMap(function (chunk) { _this.changeFileChunkStatus(chunk, interface_1.StatusCode.Uploading); _this.emit(interface_1.EventType.ChunkUploadStart, _this.task, uploadFile, chunk); // 上传单个分片,控制并发 var uploadParams = Object.assign({}, baseParams, { chunkIndex: chunk.index }); return _this.postChunk(uploadParams, uploadFile, chunk).pipe(operators_1.map(function (response) { return ({ chunk: chunk, response: response }); })); }, concurrency || 1), operators_1.tap(function (_a) { var chunk = _a.chunk, response = _a.response; shared_1.Logger.info('🚀 ~ chunk upload complete', uploadFile.name, chunk, response); _this.changeFileChunkStatus(chunk, interface_1.StatusCode.Complete); chunk.response = response === null || response === void 0 ? void 0 : response.response; _this.emit(interface_1.EventType.ChunkComplete, _this.task, uploadFile, chunk, response); }), operators_1.concatMap(function (res) { if (_this.isResumable()) { return rxjs_1.from(_this.presistChunkOnly(res.chunk)).pipe(operators_1.mapTo(res)); } else { return rxjs_1.of(res); } }), operators_1.reduce(function (acc, v) { return (acc.push(v) ? acc : acc); }, [])); }; CommonsTaskHandler.prototype.postChunk = function (params, upFile, chunk) { var _this = this; // 获取http请求相关配置 var requestOptions$ = rxjs_1.forkJoin([ this.getServerURL(upFile, chunk), this.getRequestHeaders(upFile, chunk), this.getRequestBody(upFile, params, chunk), this.getRequestMethod(upFile, chunk), this.getResponseType(upFile, chunk), ]).pipe(operators_1.map(function (_a) { var _b = tslib_1.__read(_a, 5), _c = _b[0], url = _c === void 0 ? 0 : _c, _d = _b[1], headers = _d === void 0 ? 1 : _d, _e = _b[2], body = _e === void 0 ? 2 : _e, _f = _b[3], method = _f === void 0 ? 3 : _f, _g = _b[4], responseType = _g === void 0 ? 4 : _g; return ({ url: url, headers: headers, body: body, method: method, responseType: responseType }); })); return requestOptions$.pipe(operators_1.concatMap(function (res) { var progressSubscriber = new ProgressSubscriber(_this.progressSubject, _this.task, upFile, chunk); // 进度订阅 // 上传请求发送前hook var beforeUploadRequestSend = _this.uploaderOptions.beforeUploadRequestSend; var beforeSend = _this.hookWrap(beforeUploadRequestSend === null || beforeUploadRequestSend === void 0 ? void 0 : beforeUploadRequestSend(_this.task, upFile, chunk, res)); return rxjs_1.from(beforeSend).pipe(operators_1.concatMap(function () { return _this.sendRequest(upFile, chunk, res, progressSubscriber); })); }), operators_1.concatMap(function (response) { // 上传响应数据处理前hook var beforeUploadResponseProcess = _this.uploaderOptions.beforeUploadResponseProcess; var beforeProcess = _this.hookWrap(beforeUploadResponseProcess === null || beforeUploadResponseProcess === void 0 ? void 0 : beforeUploadResponseProcess(_this.task, upFile, chunk, response)); return rxjs_1.from(beforeProcess).pipe(operators_1.mapTo(response)); }), operators_1.tap(function (response) { shared_1.Logger.info('🚀 ~ AjaxResponse', upFile.name, chunk, response); // 请求响应参数校验,200状态码认为是成功 assert_1.assert(response.status === 200, JSON.stringify(response.response)); }), operators_2.retryWithDelay(this.uploaderOptions.maxRetryTimes, this.uploaderOptions.retryInterval), // 根据配置进行重试 operators_1.catchError(function (err) { _this.changeFileChunkStatus(chunk, interface_1.StatusCode.Error); _this.emit(interface_1.EventType.ChunkError, _this.task, upFile, chunk, err); return rxjs_1.throwError(err); })); }; CommonsTaskHandler.prototype.sendRequest = function (upfile, chunk, requestOpts, progressSubscriber) { var _a = this.uploaderOptions, requestOptions = _a.requestOptions, requestBodyProcessFn = _a.requestBodyProcessFn; var url = requestOpts.url, headers = requestOpts.headers, body = requestOpts.body, method = requestOpts.method, responseType = requestOpts.responseType; var processRequestBody$ = this.toObserverble((requestBodyProcessFn === null || requestBodyProcessFn === void 0 ? void 0 : requestBodyProcessFn(this.task, upfile, chunk, body)) || this.toFormData(body)); return processRequestBody$.pipe(operators_1.concatMap(function (body) { return ajax_1.ajax({ url: url, headers: headers, body: body, method: method || 'POST', responseType: responseType, progressSubscriber: progressSubscriber, withCredentials: !!requestOptions.withCredentials, timeout: requestOptions.timeout || 0, }); })); }; CommonsTaskHandler.prototype.generateFileChunks = function (chunkSize, file) { return new rxjs_1.Observable(function (ob) { try { var start = 0; var end = 0; var chunkList = []; var chunkCount = Math.max(1, Math.ceil(file.size / chunkSize)); for (var index = 0; index < chunkCount; index++) { start = end; end = index + 1 === chunkCount ? file.size : end + chunkSize; chunkList.push(helpers_1.chunkFactory(file.id + '-' + index, index, start, end, end - start)); } ob.next(chunkList); ob.complete(); } catch (error) { ob.error(error); } }); }; CommonsTaskHandler.prototype.getRequestBody = function (uploadFile, uploadParams, chunk) { var _this = this; return new rxjs_1.Observable(function (ob) { var _a = _this.uploaderOptions, beforeFileRead = _a.beforeFileRead, fileReaded = _a.fileReaded; // 文件读取前后hook var beforeRead = _this.hookWrap(beforeFileRead === null || beforeFileRead === void 0 ? void 0 : beforeFileRead(_this.task, uploadFile, chunk)); var shouldComputeChunkHash = !!_this.uploaderOptions.computeChunkHash; var sub = rxjs_1.from(beforeRead) .pipe(operators_1.concatMap(function () { return _this.readFile(uploadFile, chunk.start, chunk.end); }), operators_1.concatMap(function (data) { // 文件读取后 var readed = _this.hookWrap(fileReaded === null || fileReaded === void 0 ? void 0 : fileReaded(_this.task, uploadFile, chunk, data)); return rxjs_1.from(readed).pipe(operators_1.mapTo(data)); }), operators_1.concatMap(function (data) { var hash$ = shouldComputeChunkHash ? _this.computeFileHash(data) : rxjs_1.of(chunk.hash || ''); return hash$.pipe(operators_1.map(function (hash) { return Object.assign(chunk, { hash: hash, data: data }); })); }), operators_1.concatMap(function (chunk) { var _a; Object.assign(uploadParams, { currentChunkSize: ((_a = chunk.data) === null || _a === void 0 ? void 0 : _a.size) || chunk.size, chunkHash: chunk.hash, file: chunk.data, }); return _this.prepareRequestParamsForChunk(uploadFile, chunk, uploadParams); })) .subscribe(ob); return function () { return sub.unsubscribe(); }; }); }; CommonsTaskHandler.prototype.prepareRequestParamsForChunk = function (uploadFile, chunk, uploadParams) { return this.getRequestParams(uploadFile, chunk, uploadParams).pipe(operators_1.map(function (userParams) { return Object.assign(uploadParams, userParams || {}); })); }; CommonsTaskHandler.prototype.handleProgress = function () { var _this = this; var reduceFn = function (res, cur) { if (res === void 0) { res = 0; } return (res += cur.uploaded || 0); }; return this.progressSubject.pipe(operators_1.map(function (_a) { var _b, _c; var chunk = _a.chunk, file = _a.file, event = _a.event; var chunkSize = ((_b = chunk.data) === null || _b === void 0 ? void 0 : _b.size) || chunk.size || event.total; var chunkLoaded = Math.min(chunkSize, event.loaded || 0); var chunkList = file.chunkList || []; chunkList[chunk.index].uploaded = chunk.uploaded = chunkLoaded; chunk.progress = Math.max(Math.round((chunkLoaded / chunkSize) * 100), chunk.progress || 0); var fileLastProgress = file.progress; var fileUploaded = chunkList.reduce(reduceFn, 0) || 0; var fileProgress = Math.round((fileUploaded / file.size) * 100); fileProgress = Math.max(Math.min(fileProgress, 100), file.progress || 0); file.uploaded = fileUploaded; file.progress = fileProgress; _this.emit(interface_1.EventType.FileProgress, _this.task, file, file.progress); if (_this.isResumable() && file.progress > fileLastProgress) { utils_1.scheduleWork(function () { return _this.presistFileOnly(file); }); } var taskLastProgress = _this.task.progress; var taskProgress = _this.task.progress; var taskUploaded = _this.task.fileList.reduce(reduceFn, 0) || 0; if (((_c = _this.task.fileIDList) === null || _c === void 0 ? void 0 : _c.length) === 1) { taskProgress = Math.max(file.progress, _this.task.progress || 0); } else { taskProgress = Math.round((taskUploaded / _this.task.fileSize) * 100); taskProgress = Math.max(taskProgress, _this.task.progress || 0); } _this.task.uploaded = Math.min(taskUploaded, _this.task.fileSize); _this.task.progress = taskProgress; if (_this.isResumable() && _this.task.progress > taskLastProgress) { utils_1.scheduleWork(function () { return _this.presistTaskOnly(_this.task); }); } // this.emit(EventType.TaskProgress, this.task, file, this.task.progress) return _this.task.progress; // Logger.info( // `progress - ${this.task.name} - ${file.name} - ${chunk.index}`, // chunk.progress, // file.progress, // this.task.progress, // ) }), operators_1.distinctUntilChanged(), operators_1.tap(function (taskProgress) { _this.emit(interface_1.EventType.TaskProgress, _this.task, taskProgress); })); }; CommonsTaskHandler.prototype.putToTaskFileList = function (uploadFile) { if (uploadFile) { this.task.fileList = this.task.fileList || []; var index = this.task.fileList.findIndex(function (f) { return f.id === uploadFile.id; }); index !== -1 ? this.task.fileList.splice(index, 1, uploadFile) : this.task.fileList.push(uploadFile); } return uploadFile; }; CommonsTaskHandler.prototype.changeUploadFileStatus = function (uploadFile, status) { uploadFile.status = status; }; CommonsTaskHandler.prototype.changeFileChunkStatus = function (chunk, status) { chunk.status = status; }; CommonsTaskHandler.prototype.changeUplotaTaskStatus = function (task, status) { task.status = status; }; return CommonsTaskHandler; }(TaskHandler_1.TaskHandler)); exports.CommonsTaskHandler = CommonsTaskHandler; var ProgressSubscriber = /** @class */ (function (_super) { tslib_1.__extends(ProgressSubscriber, _super); function ProgressSubscriber(subject, task, file, chunk) { var _this = _super.call(this) || this; _this.subject = subject; _this.task = task; _this.file = file; _this.chunk = chunk; return _this; } ProgressSubscriber.prototype.next = function (data) { this.subject.next({ task: this.task, file: this.file, chunk: this.chunk, event: data, }); }; ProgressSubscriber.prototype.error = function (e) { shared_1.Logger.error('progress error', e); }; return ProgressSubscriber; }(rxjs_1.Subscriber)); //# sourceMappingURL=CommonsTaskHandler.js.map