js-uploader
Version:
A JavaScript library for file upload
695 lines • 39.7 kB
JavaScript
"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