2022-04-27 20:32:35 -04:00
|
|
|
const FILE_CHUNK_SIZE = 16384;
|
2022-04-28 00:27:22 -04:00
|
|
|
const MAX_FILES = 256;
|
2022-04-27 20:32:35 -04:00
|
|
|
|
2022-04-27 23:52:45 -04:00
|
|
|
const fileInputContainer = document.getElementById('file_input_container');
|
|
|
|
const fileInput = document.getElementById('file_input');
|
|
|
|
const fileInputMessage = document.getElementById('file_input_message');
|
|
|
|
|
|
|
|
const fileListContainer = document.getElementById('file_list_container');
|
|
|
|
const fileList = document.getElementById('file_list');
|
|
|
|
|
|
|
|
const uploadButton = document.getElementById('upload');
|
|
|
|
|
|
|
|
const downloadLinkContainer = document.getElementById('download_link_container');
|
|
|
|
const downloadLink = document.getElementById('download_link');
|
|
|
|
|
|
|
|
const progressContainer = document.getElementById('progress_container');
|
|
|
|
const progress = document.getElementById('progress');
|
|
|
|
const progressBarFilled = document.getElementById('progress_bar_filled');
|
|
|
|
|
2022-04-26 23:54:29 -04:00
|
|
|
let files = [];
|
|
|
|
|
|
|
|
let socket = null;
|
|
|
|
let fileIndex = 0;
|
|
|
|
let byteIndex = 0;
|
2022-04-27 12:59:14 -04:00
|
|
|
let bytesSent = 0;
|
|
|
|
let totalBytes = 0;
|
2022-04-26 23:54:29 -04:00
|
|
|
|
|
|
|
function sendMetadata() {
|
|
|
|
const metadata = files.map((file) => ({
|
|
|
|
name: file.name,
|
|
|
|
size: file.size,
|
|
|
|
modtime: file.lastModified,
|
|
|
|
}));
|
|
|
|
socket.send(JSON.stringify(metadata));
|
|
|
|
}
|
|
|
|
|
|
|
|
function finishSending() {
|
|
|
|
if (socket.bufferedAmount > 0) {
|
|
|
|
window.setTimeout(finishSending, 1000);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
socket.close();
|
2022-04-27 23:52:45 -04:00
|
|
|
progressContainer.textContent = "Upload complete!";
|
2022-04-26 23:54:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
function sendData() {
|
|
|
|
if (fileIndex >= files.length) {
|
|
|
|
finishSending();
|
2022-04-27 13:03:35 -04:00
|
|
|
return;
|
2022-04-26 23:54:29 -04:00
|
|
|
}
|
|
|
|
const currentFile = files[fileIndex];
|
|
|
|
if (byteIndex < currentFile.size) {
|
2022-04-27 20:32:35 -04:00
|
|
|
const endpoint = Math.min(byteIndex+FILE_CHUNK_SIZE, currentFile.size);
|
2022-04-26 23:54:29 -04:00
|
|
|
const data = currentFile.slice(byteIndex, endpoint);
|
|
|
|
socket.send(data);
|
|
|
|
byteIndex = endpoint;
|
2022-04-27 12:59:14 -04:00
|
|
|
bytesSent += data.size;
|
2022-04-27 23:52:45 -04:00
|
|
|
updateProgress();
|
2022-04-26 23:54:29 -04:00
|
|
|
} else {
|
|
|
|
fileIndex += 1;
|
|
|
|
byteIndex = 0;
|
|
|
|
sendData();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-27 23:52:45 -04:00
|
|
|
function updateProgress() {
|
|
|
|
let percentage;
|
|
|
|
if (totalBytes === 0) {
|
|
|
|
percentage = "0%";
|
|
|
|
} else {
|
|
|
|
percentage = `${(bytesSent*100/totalBytes).toFixed(1)}%`;
|
|
|
|
}
|
|
|
|
progress.textContent = percentage;
|
|
|
|
progressBarFilled.style.width = percentage;
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateFiles() {
|
|
|
|
totalBytes = files.reduce((acc, file) => acc + file.size, 0);
|
2022-04-26 23:54:29 -04:00
|
|
|
|
|
|
|
if (files.length === 0) {
|
|
|
|
fileInputMessage.textContent = 'Select files to upload...';
|
2022-04-27 23:52:45 -04:00
|
|
|
fileListContainer.style.display = 'none';
|
|
|
|
uploadButton.style.display = 'none';
|
2022-04-26 23:54:29 -04:00
|
|
|
} else {
|
|
|
|
fileInputMessage.textContent = 'Select more files to upload...';
|
2022-04-27 23:52:45 -04:00
|
|
|
fileListContainer.style.display = '';
|
|
|
|
uploadButton.textContent = `Upload ${files.length} file${files.length > 1 ? 's' : ''} (${displaySize(totalBytes)})`;
|
|
|
|
uploadButton.style.display = '';
|
2022-04-26 23:54:29 -04:00
|
|
|
}
|
2022-04-28 00:27:22 -04:00
|
|
|
fileInput.disabled = (files.length >= MAX_FILES);
|
2022-04-26 23:54:29 -04:00
|
|
|
}
|
|
|
|
|
2022-04-27 23:52:45 -04:00
|
|
|
updateFiles();
|
|
|
|
downloadLinkContainer.style.display = 'none';
|
|
|
|
progressContainer.style.display = 'none';
|
2022-04-26 23:54:29 -04:00
|
|
|
|
|
|
|
function addFile(newFile) {
|
2022-04-28 00:27:22 -04:00
|
|
|
if (files.length >= MAX_FILES) { return; }
|
2022-04-26 23:54:29 -04:00
|
|
|
if (files.some((oldFile) => newFile.name === oldFile.name)) { return; }
|
|
|
|
|
|
|
|
files.push(newFile);
|
|
|
|
|
2022-04-27 23:52:45 -04:00
|
|
|
addListEntry(newFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
function addListEntry(file) {
|
|
|
|
const listEntry = document.createElement('tr');
|
|
|
|
|
|
|
|
const deleteButtonCell = document.createElement('td');
|
2022-04-26 23:54:29 -04:00
|
|
|
const deleteButton = document.createElement('button');
|
2022-04-27 23:52:45 -04:00
|
|
|
deleteButtonCell.appendChild(deleteButton);
|
|
|
|
deleteButton.className = 'file_delete';
|
2022-04-26 23:54:29 -04:00
|
|
|
deleteButton.textContent = 'x';
|
|
|
|
deleteButton.addEventListener('click', () => {
|
2022-04-27 23:52:45 -04:00
|
|
|
removeFile(file.name);
|
2022-04-26 23:54:29 -04:00
|
|
|
listEntry.remove();
|
2022-04-27 23:52:45 -04:00
|
|
|
updateFiles();
|
2022-04-26 23:54:29 -04:00
|
|
|
});
|
2022-04-27 23:52:45 -04:00
|
|
|
|
|
|
|
const sizeCell = document.createElement('td');
|
|
|
|
sizeCell.className = 'file_size';
|
|
|
|
sizeCell.textContent = displaySize(file.size);
|
|
|
|
|
|
|
|
const nameCell = document.createElement('td');
|
|
|
|
nameCell.className = 'file_name';
|
|
|
|
nameCell.textContent = file.name;
|
|
|
|
|
|
|
|
listEntry.appendChild(deleteButtonCell);
|
|
|
|
listEntry.appendChild(sizeCell);
|
|
|
|
listEntry.appendChild(nameCell);
|
2022-04-26 23:54:29 -04:00
|
|
|
|
|
|
|
fileList.appendChild(listEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
function removeFile(name) {
|
|
|
|
files = files.filter((file) => file.name !== name);
|
|
|
|
}
|
|
|
|
|
|
|
|
fileInput.addEventListener('input', (e) => {
|
|
|
|
for (const file of e.target.files) { addFile(file); }
|
2022-04-27 23:52:45 -04:00
|
|
|
updateFiles();
|
2022-04-26 23:54:29 -04:00
|
|
|
e.target.value = '';
|
|
|
|
});
|
|
|
|
|
|
|
|
uploadButton.addEventListener('click', (e) => {
|
|
|
|
if (files.length === 0) { return; }
|
|
|
|
|
2022-04-27 23:52:45 -04:00
|
|
|
fileInputContainer.remove();
|
|
|
|
for (const button of Array.from(document.getElementsByTagName('button'))) {
|
|
|
|
button.remove();
|
2022-04-26 23:54:29 -04:00
|
|
|
}
|
|
|
|
|
2022-04-27 21:47:36 -04:00
|
|
|
socket = new WebSocket(`${window.location.protocol === 'http:' ? 'ws' : 'wss'}://${window.location.host}/upload`);
|
2022-04-26 23:54:29 -04:00
|
|
|
socket.addEventListener('open', sendMetadata);
|
|
|
|
socket.addEventListener('message', (msg) => {
|
2022-04-27 12:59:14 -04:00
|
|
|
if (bytesSent === 0 && msg.data.match(/^[A-Za-z0-9]+$/)) {
|
2022-04-27 21:47:36 -04:00
|
|
|
downloadLink.textContent = `${window.location.origin}/download/${msg.data}`;
|
2022-04-27 23:52:45 -04:00
|
|
|
downloadLinkContainer.style.display = '';
|
|
|
|
updateProgress();
|
|
|
|
progressContainer.style.display = '';
|
2022-04-27 12:59:14 -04:00
|
|
|
sendData();
|
|
|
|
} else if (msg.data === 'ack') {
|
2022-04-26 23:54:29 -04:00
|
|
|
sendData();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
})
|