Spaces:
Paused
Paused
/** | |
* Copyright (C) 2024 Puter Technologies Inc. | |
* | |
* This file is part of Puter. | |
* | |
* Puter is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU Affero General Public License as published | |
* by the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU Affero General Public License for more details. | |
* | |
* You should have received a copy of the GNU Affero General Public License | |
* along with this program. If not, see <https://www.gnu.org/licenses/>. | |
*/ | |
/** | |
* Launches a download process for an item, tracking its progress and handling success or error states. | |
* The function returns a promise that resolves with the downloaded item or rejects in case of an error. | |
* It uses XMLHttpRequest to manage the download and tracks progress both for the individual item and the entire batch it belongs to. | |
* | |
* @param {Object} options - Configuration options for the download process. | |
* @param {string} options.url - The URL from which the item will be downloaded. | |
* @param {string} options.operation_id - Unique identifier for the download operation, used for progress tracking. | |
* @param {string} options.item_upload_id - Identifier for the specific item being downloaded, used for individual progress tracking. | |
* @param {string} [options.name] - Optional name for the item being downloaded. | |
* @param {string} [options.dest_path] - Destination path for the downloaded item. | |
* @param {string} [options.shortcut_to] - Optional shortcut path for the item. | |
* @param {boolean} [options.dedupe_name=false] - Flag to enable or disable deduplication of item names. | |
* @param {boolean} [options.overwrite=false] - Flag to enable or disable overwriting of existing items. | |
* @param {function} [options.success] - Optional callback function that is executed on successful download. | |
* @param {function} [options.error] - Optional callback function that is executed in case of an error. | |
* @param {number} [options.return_timeout=500] - Optional timeout in milliseconds before resolving the download. | |
* @returns {Promise<Object>} A promise that resolves with the downloaded item or rejects with an error. | |
*/ | |
const download = function(options){ | |
return new Promise((resolve, reject) => { | |
// The item that is being downloaded and will be returned to the caller at the end of the process | |
let item; | |
// Intervals that check for progress and cancel every few milliseconds | |
let progress_check_interval, cancel_check_interval; | |
// Progress tracker for the entire batch to which this item belongs | |
let batch_download_progress = window.progress_tracker[options.operation_id]; | |
// Tracker for this specific item's download progress | |
let item_download_progress = batch_download_progress[options.item_upload_id]; | |
let xhr = new XMLHttpRequest(); | |
xhr.open("post", (api_origin + '/download'), true); | |
xhr.setRequestHeader("Authorization", "Bearer " + auth_token); | |
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); | |
xhr.addEventListener('load', function(e){ | |
// error | |
if(this.status !== 200){ | |
if(options.error && typeof options.error === 'function') | |
options.error(JSON.parse(this.responseText)) | |
return reject(JSON.parse(this.responseText)) | |
} | |
// success | |
else{ | |
item = JSON.parse(this.responseText); | |
} | |
}); | |
// error | |
xhr.addEventListener('error', function(e){ | |
if(options.error && typeof options.error === 'function') | |
options.error(e) | |
return reject(e) | |
}) | |
xhr.send(JSON.stringify({ | |
url: options.url, | |
operation_id: options.operation_id, | |
socket_id: window.socket ? window.socket.id : null, | |
item_upload_id: options.item_upload_id, | |
// original_client_socket_id: window.socket.id, | |
name: options.name, | |
path: options.dest_path, | |
shortcut_to: options.shortcut_to, | |
dedupe_name: options.dedupe_name ?? false, | |
overwrite: options.overwrite ?? false, | |
})); | |
//---------------------------------------------- | |
// Regularly check if this operation has been cancelled by the user | |
//---------------------------------------------- | |
cancel_check_interval = setInterval(() => { | |
if(operation_cancelled[options.operation_id]){ | |
xhr.abort(); | |
clearInterval(cancel_check_interval); | |
clearInterval(progress_check_interval); | |
} | |
}, 100); | |
//---------------------------------------------- | |
// Regularly check the progress of the cloud-write operation | |
//---------------------------------------------- | |
progress_check_interval = setInterval(function() { | |
// Individual item progress | |
let item_progress = 1; | |
if(item_download_progress.total) | |
item_progress = (item_download_progress.cloud_uploaded + item_download_progress.downloaded) / item_download_progress.total; | |
// Entire batch progress | |
let batch_progress = ((batch_download_progress[0].cloud_uploaded + batch_download_progress[0].downloaded)/batch_download_progress[0].total * 100).toFixed(0); | |
batch_progress = batch_progress > 100 ? 100 : batch_progress; | |
// Update the progress bar | |
$(`[data-download-operation-id="${options.operation_id}"]`).find('.download-progress-bar').css( 'width', batch_progress+'%'); | |
// If download is finished resolve promise | |
if((item_progress >= 1 || item_progress === 0) && item){ | |
// For a better UX, resolve 0.5 second after operation is finished. | |
setTimeout(function() { | |
clearInterval(progress_check_interval); | |
clearInterval(cancel_check_interval); | |
if(options.success && typeof options.success === 'function'){ | |
options.success(item) | |
} | |
resolve(item); | |
}, options.return_timeout ?? 500); | |
// Stop and clear the the cloud progress check interval | |
clearInterval(progress_check_interval) | |
} | |
}, 200); | |
return xhr; | |
}) | |
} | |
export default download; |