Files
fnx_web/res/include/script/dependencies/UploadManager.js

167 lines
4.0 KiB
JavaScript
Raw Normal View History

2020-02-11 13:58:19 +01:00
function UploadManager(uploadEndpoint, uploadsFinished) {
this.uploadEndpoint = uploadEndpoint;
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Callback function for when the queue is empty
2020-01-28 12:51:21 +01:00
this.uploadsFinished = uploadsFinished;
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Counts the total number of upload jobs
2020-01-28 12:51:21 +01:00
this.jobCounter = 0;
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Queue of files to be uploaded. Format:
// {
// jobID: number,
// file: Blob,
// name: string,
// onProgress: function,
// onFinished: function,
// onFailure: function,
// tries: number
// }
2020-01-28 12:51:21 +01:00
this.uploadQueue = [];
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Here we put successful jobs. The array should be sorted by job ID.
// Format:
// { jobID: number, fileID: string, fileName: string }
2020-01-28 12:51:21 +01:00
this.uploadLog = [];
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Max number of uploading threads at once
2020-01-28 12:51:21 +01:00
this.maxWorkers = 3;
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Threads which are currently uploading
2020-01-28 12:51:21 +01:00
this.activeWorkers = 0;
2020-01-27 16:56:16 +01:00
// Total number of jobs accepted
2020-01-28 12:51:21 +01:00
this.jobCounter = 0;
2020-01-27 16:56:16 +01:00
}
2021-01-11 21:43:04 +01:00
UploadManager.prototype.finishedUploads = function () {
2020-01-28 12:51:21 +01:00
this.uploadLog.sort((a, b) => {
2020-01-27 16:56:16 +01:00
return a.jobID - b.jobID;
})
2020-01-28 12:51:21 +01:00
return this.uploadLog;
2020-01-27 16:56:16 +01:00
}
2021-01-11 21:43:04 +01:00
UploadManager.prototype.addFile = function (
2020-01-27 16:56:16 +01:00
file, // Blob
name, // string
onProgress, // func (progress: number)
onFinished, // func (id: string)
onFailure // func (errorID: string, errorMessage: string)
2020-01-28 12:51:21 +01:00
) {
this.uploadQueue.push({
jobID: this.jobCounter,
2020-01-27 16:56:16 +01:00
file: file,
name: name,
onProgress: onProgress,
onFinished: onFinished,
onFailure: onFailure,
tries: 0
});
// Increment the job counter
2020-01-28 12:51:21 +01:00
this.jobCounter++
2020-01-27 16:56:16 +01:00
2020-01-28 12:51:21 +01:00
if (this.activeWorkers < this.maxWorkers) {
2020-01-27 16:56:16 +01:00
// Run the upload function
2020-01-28 12:51:21 +01:00
this.startUpload();
2020-01-20 12:43:43 +01:00
}
2020-01-27 16:56:16 +01:00
}
2021-01-11 21:43:04 +01:00
UploadManager.prototype.startUpload = function () {
2020-01-28 12:51:21 +01:00
if (this.uploadQueue.length === 0) {
2020-01-27 16:56:16 +01:00
return; // Nothing to upload
}
2020-01-20 12:43:43 +01:00
2020-01-28 12:51:21 +01:00
if (this.activeWorkers < this.maxWorkers) {
this.activeWorkers++;
this.uploadThread();
2020-01-27 16:56:16 +01:00
}
}
2021-01-11 21:43:04 +01:00
UploadManager.prototype.finishUpload = function () {
2020-01-28 12:51:21 +01:00
this.activeWorkers--;
2020-01-27 16:56:16 +01:00
if (
2020-01-28 12:51:21 +01:00
this.uploadQueue.length === 0 &&
this.activeWorkers === 0 &&
2021-01-11 21:43:04 +01:00
typeof (this.uploadsFinished) === "function"
2020-01-27 16:56:16 +01:00
) {
2020-01-28 12:51:21 +01:00
this.uploadsFinished();
2020-01-27 16:56:16 +01:00
return;
}
// Run the upload function for the next file
2020-01-28 12:51:21 +01:00
this.startUpload();
2020-01-27 16:56:16 +01:00
}
2021-01-11 21:43:04 +01:00
UploadManager.prototype.uploadThread = function () {
2020-01-28 12:51:21 +01:00
let job = this.uploadQueue.shift(); // Get the first element of the array
2020-01-27 16:56:16 +01:00
console.debug("Starting upload of " + job.name);
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
let form = new FormData();
2020-02-11 21:52:14 +01:00
form.append('file', job.file, job.name);
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
let xhr = new XMLHttpRequest();
2020-02-11 13:58:19 +01:00
xhr.open("POST", this.uploadEndpoint, true);
2020-01-27 16:56:16 +01:00
xhr.timeout = 21600000; // 6 hours, to account for slow connections
2020-01-20 12:43:43 +01:00
2020-01-27 16:56:16 +01:00
// Report progress updates back to the caller
2020-01-28 12:51:21 +01:00
xhr.upload.addEventListener("progress", evt => {
2021-01-11 21:43:04 +01:00
if (evt.lengthComputable && typeof (job.onProgress) === "function") {
2020-01-27 16:56:16 +01:00
job.onProgress(evt.loaded / evt.total);
}
});
2020-01-28 12:51:21 +01:00
xhr.onreadystatechange = () => {
2020-01-27 16:56:16 +01:00
// readystate 4 means the upload is done
if (xhr.readyState !== 4) { return; }
if (xhr.status >= 100 && xhr.status < 400) {
// Request is a success
let resp = JSON.parse(xhr.response);
addUploadHistory(resp.id)
// Log the successful job
2020-01-28 12:51:21 +01:00
this.uploadLog.push({
2020-01-27 16:56:16 +01:00
jobID: job.jobID,
fileID: resp.id,
fileName: job.name
});
2021-01-11 21:43:04 +01:00
if (typeof (job.onFinished) === "function") {
2020-01-27 16:56:16 +01:00
job.onFinished(resp.id);
2020-01-20 12:43:43 +01:00
}
2020-01-21 17:13:18 +01:00
2020-01-27 16:56:16 +01:00
// Finish the upload job
2020-01-28 12:51:21 +01:00
this.finishUpload();
2020-01-27 16:56:16 +01:00
} else if (xhr.status >= 400) {
// Request failed
console.log("Upload error. status: " + xhr.status + " response: " + xhr.response);
let resp = JSON.parse(xhr.response);
2021-01-11 21:43:04 +01:00
if (resp.value == "file_too_large" || job.tries === 3) { // Upload failed
2020-01-27 16:56:16 +01:00
job.onFailure(resp.value, resp.message);
} else { // Try again
job.tries++;
2020-01-28 12:51:21 +01:00
this.uploadQueue.push(job);
2020-01-27 16:56:16 +01:00
}
2020-01-21 17:13:18 +01:00
2020-01-27 16:56:16 +01:00
// Sleep the upload thread for 5 seconds
2020-01-28 12:51:21 +01:00
window.setTimeout(() => { this.finishUpload(); }, 5000);
2020-01-27 16:56:16 +01:00
} else {
// Request did not arrive
if (job.tries === 3) { // Upload failed
2021-01-11 21:43:04 +01:00
if (typeof (job.onFailure) === "function") {
2020-01-31 21:02:37 +01:00
job.onFailure(xhr.responseText, xhr.responseText);
2020-01-20 12:43:43 +01:00
}
2020-01-27 16:56:16 +01:00
} else { // Try again
job.tries++;
2020-01-28 12:51:21 +01:00
this.uploadQueue.push(job);
2020-01-21 17:13:18 +01:00
}
2020-01-27 16:56:16 +01:00
// Sleep the upload thread for 5 seconds
2020-01-28 12:51:21 +01:00
window.setTimeout(() => { this.finishUpload(); }, 5000);
2020-01-27 16:56:16 +01:00
}
};
xhr.send(form);
2020-01-20 12:43:43 +01:00
}