js-uploader
Version:
A JavaScript library for file upload
692 lines • 37.4 kB
JavaScript
import { __extends, __read, __spread } from "tslib";
import { TaskHandler } from './TaskHandler';
import { EventType, StatusCode, } from '../../interface';
import { forkJoin, from, Observable, Subscriber, of, Subject, throwError, scheduled, asyncScheduler, BehaviorSubject, } from 'rxjs';
import { tap, map, concatMap, filter, catchError, mergeMap, mapTo, switchMap, reduce, distinctUntilChanged, takeUntil, bufferCount, takeWhile, } from 'rxjs/operators';
import { ajax } from 'rxjs/ajax';
import { retryWithDelay } from '../../operators';
import { assert } from '../../utils/assert';
import { chunkFactory } from '../helpers';
import { scheduleWork } from '../../utils';
import { Logger } from '../../shared';
var SubjectAction;
(function (SubjectAction) {
SubjectAction["AbortFile"] = "abort-file";
SubjectAction["PauseFile"] = "pause-file";
})(SubjectAction || (SubjectAction = {}));
var CommonsTaskHandler = /** @class */ (function (_super) {
__extends(CommonsTaskHandler, _super);
function CommonsTaskHandler() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.progressSubject = new Subject();
_this.upload$ = null;
_this.subscription = null;
_this.subject = new BehaviorSubject({});
_this.uploadFileIDSubject = new 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 === StatusCode.Complete ? task.status : StatusCode.Pause;
this.isResumable() && this.presistTaskOnly(this.task);
scheduled(task.fileList || [], asyncScheduler)
.pipe(tap(function (file) {
var status = file.status === StatusCode.Complete || file.status === StatusCode.Error ? file.status : StatusCode.Pause;
_this.changeUploadFileStatus(file, status);
_this.emit(EventType.FilePause, task, file);
_this.isResumable() && _this.presistFileOnly(file);
}))
.subscribe();
this.emit(EventType.TaskPause, this.task);
return this;
};
CommonsTaskHandler.prototype.resume = function () {
this.handle().emit(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 === StatusCode.Error; })) || [];
scheduled(errorFiles, asyncScheduler).subscribe({
next: function (file) {
_this.changeUploadFileStatus(file, StatusCode.Pause);
_this.emit(EventType.FilePause, _this.task, file);
},
complete: function () {
_this.handle().emit(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(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 = [];
scheduled(files, asyncScheduler)
.pipe(bufferCount(100), concatMap(function (files) {
return from(files).pipe(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 !== StatusCode.Complete && rawFile.status !== StatusCode.Error) {
_this.changeUploadFileStatus(rawFile, StatusCode.Pause);
_this.emit(EventType.FilePause, _this.task, rawFile);
rawFiles.push(rawFile);
}
}));
}))
.subscribe({
complete: function () {
_this.emit(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];
}
scheduled(files, asyncScheduler)
.pipe(bufferCount(100), concatMap(function (files) {
return from(files).pipe(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], StatusCode.Pause);
_this.task.fileList.splice(fileIndex, 1);
}
_this.emit(EventType.FileCancel, _this.task, file);
_this.emit(EventType.TaskUpdate, _this.task);
}));
}))
.subscribe({
complete: function () {
_this.emit(EventType.FilesCancel, _this.task, files);
},
});
return this;
};
CommonsTaskHandler.prototype.handle = function () {
var _this = this;
var _a;
Logger.info('CommonTaskHandler -> handle -> task', this.task);
if (!this.upload$) {
this.upload$ = of(this.task).pipe(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 from(beforeTaskStart).pipe(mapTo(task));
}), tap(function (task) {
Logger.info('🚀 ~ 开始上传', task);
_this.changeUplotaTaskStatus(task, StatusCode.Uploading);
_this.emit(EventType.TaskUploadStart, task);
}), switchMap(function () { return _this.createUploadJob(); }));
}
(_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
this.subscription = this.upload$.subscribe({
next: function () {
Logger.info('🚀 ~ 上传任务 next ');
},
error: function (err) {
Logger.info('🚀 ~ 上传任务出错', err);
_this.changeUplotaTaskStatus(_this.task, StatusCode.Error);
_this.emit(EventType.TaskError, _this.task, err);
},
complete: function () {
Logger.info('🚀 ~ 上传任务完成', _this.task);
if (_this.task.fileList.every(function (i) { return i.status === StatusCode.Complete; })) {
_this.changeUplotaTaskStatus(_this.task, StatusCode.Complete);
_this.emit(EventType.TaskComplete, _this.task);
// this.removeTaskFromStroage(this.task)
}
else if (_this.task.fileList.some(function (i) { return i.status === StatusCode.Error; })) {
_this.changeUplotaTaskStatus(_this.task, StatusCode.Error);
_this.emit(EventType.TaskError, _this.task);
}
else if (_this.task.fileList.some(function (i) { return i.status === StatusCode.Pause; })) {
_this.changeUplotaTaskStatus(_this.task, StatusCode.Pause);
_this.emit(EventType.TaskPause, _this.task);
}
_this.uploaderOptions.resumable && _this.presistTaskOnly(_this.task);
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$ = of(this.task).pipe(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 from(beforeTaskStart).pipe(mapTo(task));
}), tap(function (task) {
Logger.info('🚀 ~ 开始上传', task);
_this.changeUplotaTaskStatus(task, StatusCode.Uploading);
_this.emit(EventType.TaskUploadStart, task);
}), switchMap(function () {
return _this.uploadFileIDSubject.pipe(mergeMap(function (id) { return _this.executeForResult(id); }, 2), tap(function () { }), 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 () {
Logger.info('🚀 ~ 上传任务 next ');
},
error: function (err) {
Logger.info('🚀 ~ 上传任务出错', err);
_this.changeUplotaTaskStatus(_this.task, StatusCode.Error);
_this.emit(EventType.TaskError, _this.task, err);
},
complete: function () {
Logger.info('🚀 ~ 上传任务完成', _this.task);
if (_this.task.fileList.every(function (i) { return i.status === StatusCode.Complete; })) {
_this.changeUplotaTaskStatus(_this.task, StatusCode.Complete);
_this.emit(EventType.TaskComplete, _this.task);
_this.removeTaskFromStroage(_this.task);
}
else if (_this.task.fileList.some(function (i) { return i.status === StatusCode.Pause || i.status === StatusCode.Error; })) {
_this.changeUplotaTaskStatus(_this.task, StatusCode.Pause);
_this.emit(EventType.TaskPause, _this.task);
}
},
});
this.subscription.add(this.handleProgress().subscribe());
if (uploadFiles === null || uploadFiles === void 0 ? void 0 : uploadFiles.length) {
scheduled(uploadFiles, asyncScheduler).subscribe(function (file) { return _this.putNextFile(file); });
}
else {
this.putNextFile();
}
return this;
};
CommonsTaskHandler.prototype.executeForResult = function (fileID) {
var _this = this;
return of(fileID).pipe(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 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 {
scheduled(this.task.fileIDList, asyncScheduler).subscribe(function (id) { return _this.uploadFileIDSubject.next(id); });
}
};
CommonsTaskHandler.prototype.createFileUploadJob = function (fileID) {
var _this = this;
var pocessed = [];
return of(fileID).pipe(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;
}), concatMap(function (fileID) {
// 根据ID获取文件
return _this.getUploadFileByID(fileID).pipe(map(function (uploadFile) {
assert(!!uploadFile, 'file not found! ID:' + fileID);
return _this.putToTaskFileList(uploadFile);
}));
}), filter(function (uploadFile) {
// 过滤完成的文件
var isComplete = uploadFile.status === StatusCode.Complete;
if (isComplete) {
pocessed.push(uploadFile.id);
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
// }),
tap(function (uploadFile) {
_this.changeUploadFileStatus(uploadFile, StatusCode.Waiting);
_this.emit(EventType.FileWaiting, _this.task, uploadFile);
}), concatMap(function (uploadFile) {
var ob$ = _this.uploadFile(uploadFile).pipe(tap(function () {
pocessed.push(uploadFile.id);
}));
return ob$;
}));
};
CommonsTaskHandler.prototype.createUploadJob = function () {
var _this = this;
return scheduled(this.task.fileIDList || [], asyncScheduler).pipe(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)));
}), concatMap(function (fileID) {
// 根据ID获取文件
return _this.getUploadFileByID(fileID).pipe(map(function (uploadFile) {
assert(!!uploadFile, 'file not found! ID:' + fileID);
return _this.putToTaskFileList(uploadFile);
}));
}), filter(function (uploadFile) {
// 过滤完成的文件
var isComplete = uploadFile.status === StatusCode.Complete;
if (isComplete) {
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
// }),
tap(function (uploadFile) {
_this.changeUploadFileStatus(uploadFile, StatusCode.Waiting);
_this.emit(EventType.FileWaiting, _this.task, uploadFile);
}), 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 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 of(uploadFile).pipe(concatMap(function (uploadFile) {
_this.changeUploadFileStatus(uploadFile, StatusCode.Uploading);
// 判断是否需要计算hash/md5
var should = !!uploaderOptions.computeFileHash && !uploadFile.hash;
if (!should) {
Logger.info('should not compute hash for', uploadFile.name);
return 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 from(beforeCompute).pipe(concatMap(function () {
// 使用线程池计算hash
return _this.computeFileMd5ByWorker(uploadFile).pipe(map(function (hash) { return Object.assign(uploadFile, { hash: hash }); }));
}), concatMap(function (uploadFile) {
// hash计算后
var computed = _this.hookWrap(fileHashComputed === null || fileHashComputed === void 0 ? void 0 : fileHashComputed(task, uploadFile, uploadFile.hash));
return from(computed).pipe(mapTo(uploadFile));
}));
}), 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 from(beforeFileUploadStart).pipe(mapTo(uploadFile));
}), filter(function (uploadFile) {
return uploadFile.status !== StatusCode.Complete && uploadFile.status !== StatusCode.Pause;
}), // 再次过滤成功的文件
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 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(concatMap(function (chunkList) {
var chunkIDList = chunkList.map(function (ck) { return ck.id; });
Object.assign(uploadFile, { chunkList: chunkList, chunkIDList: chunkIDList });
// 保存分片和文件信息
if (_this.isResumable()) {
return forkJoin([from(_this.presistChunkOnly.apply(_this, __spread(chunkList))), from(_this.presistFileOnly(uploadFile))]);
}
else {
return of('');
}
}), mapTo(uploadFile));
}), concatMap(function (uploadFile) {
// 文件上传事件
_this.emit(EventType.FileUploadStart, _this.task, uploadFile);
var concurrency = uploaderOptions.chunkConcurrency || 1;
// 上传所有分片并控制并发
return _this.uploadChunks(uploadFile, concurrency).pipe(map(function (chunkResponses) { return ({ uploadFile: uploadFile, chunkResponses: chunkResponses }); }));
}), 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 from(beforeComplete).pipe(mapTo(res));
}), catchError(function (e) {
Logger.info('🚀 ~ upload error', uploadFile, e);
// 文件上传错误事件
_this.changeUploadFileStatus(uploadFile, StatusCode.Error);
_this.emit(EventType.FileError, _this.task, uploadFile, e);
_this.presistFileOnly(uploadFile);
// 错误处理 判断是否需要过滤该文件
if (!uploaderOptions.skipFileWhenUploadError) {
return throwError(e);
}
else {
return of({ uploadFile: uploadFile, chunkResponses: [] });
}
}), tap(function (_a) {
var _b, _c;
var uploadFile = _a.uploadFile, chunkResponses = _a.chunkResponses;
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 !== StatusCode.Error) {
_this.changeUploadFileStatus(uploadFile, StatusCode.Complete);
_this.emit(EventType.FileComplete, _this.task, uploadFile, chunkResponses);
}
_this.presistFileOnly(uploadFile);
}), takeUntil(this.subject.pipe(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));
}), tap(function () { return _this.changeUploadFileStatus(uploadFile, 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 scheduled(chunkList || [], asyncScheduler).pipe(filter(function (chunk) {
// 过滤完成的分片
var isComplete = chunk.status === StatusCode.Complete;
if (isComplete) {
Logger.info("skip chunk\uFF0Cstatus:" + chunk.status, uploadFile.name, chunk);
}
return !isComplete;
}), tap(function (chunk) {
_this.changeFileChunkStatus(chunk, StatusCode.Waiting);
}), mergeMap(function (chunk) {
_this.changeFileChunkStatus(chunk, StatusCode.Uploading);
_this.emit(EventType.ChunkUploadStart, _this.task, uploadFile, chunk);
// 上传单个分片,控制并发
var uploadParams = Object.assign({}, baseParams, { chunkIndex: chunk.index });
return _this.postChunk(uploadParams, uploadFile, chunk).pipe(map(function (response) { return ({ chunk: chunk, response: response }); }));
}, concurrency || 1), tap(function (_a) {
var chunk = _a.chunk, response = _a.response;
Logger.info('🚀 ~ chunk upload complete', uploadFile.name, chunk, response);
_this.changeFileChunkStatus(chunk, StatusCode.Complete);
chunk.response = response === null || response === void 0 ? void 0 : response.response;
_this.emit(EventType.ChunkComplete, _this.task, uploadFile, chunk, response);
}), concatMap(function (res) {
if (_this.isResumable()) {
return from(_this.presistChunkOnly(res.chunk)).pipe(mapTo(res));
}
else {
return of(res);
}
}), reduce(function (acc, v) { return (acc.push(v) ? acc : acc); }, []));
};
CommonsTaskHandler.prototype.postChunk = function (params, upFile, chunk) {
var _this = this;
// 获取http请求相关配置
var requestOptions$ = forkJoin([
this.getServerURL(upFile, chunk),
this.getRequestHeaders(upFile, chunk),
this.getRequestBody(upFile, params, chunk),
this.getRequestMethod(upFile, chunk),
this.getResponseType(upFile, chunk),
]).pipe(map(function (_a) {
var _b = __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(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 from(beforeSend).pipe(concatMap(function () { return _this.sendRequest(upFile, chunk, res, progressSubscriber); }));
}), 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 from(beforeProcess).pipe(mapTo(response));
}), tap(function (response) {
Logger.info('🚀 ~ AjaxResponse', upFile.name, chunk, response);
// 请求响应参数校验,200状态码认为是成功
assert(response.status === 200, JSON.stringify(response.response));
}), retryWithDelay(this.uploaderOptions.maxRetryTimes, this.uploaderOptions.retryInterval), // 根据配置进行重试
catchError(function (err) {
_this.changeFileChunkStatus(chunk, StatusCode.Error);
_this.emit(EventType.ChunkError, _this.task, upFile, chunk, err);
return 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(concatMap(function (body) {
return 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 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(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 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 = from(beforeRead)
.pipe(concatMap(function () { return _this.readFile(uploadFile, chunk.start, chunk.end); }), concatMap(function (data) {
// 文件读取后
var readed = _this.hookWrap(fileReaded === null || fileReaded === void 0 ? void 0 : fileReaded(_this.task, uploadFile, chunk, data));
return from(readed).pipe(mapTo(data));
}), concatMap(function (data) {
var hash$ = shouldComputeChunkHash ? _this.computeFileHash(data) : of(chunk.hash || '');
return hash$.pipe(map(function (hash) { return Object.assign(chunk, { hash: hash, data: data }); }));
}), 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(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(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(EventType.FileProgress, _this.task, file, file.progress);
if (_this.isResumable() && file.progress > fileLastProgress) {
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) {
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,
// )
}), distinctUntilChanged(), tap(function (taskProgress) {
_this.emit(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));
export { CommonsTaskHandler };
var ProgressSubscriber = /** @class */ (function (_super) {
__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) {
Logger.error('progress error', e);
};
return ProgressSubscriber;
}(Subscriber));
//# sourceMappingURL=CommonsTaskHandler.js.map