const FILE_CHUNK_SIZE = 16384; let files = []; let socket = null; let fileIndex = 0; let byteIndex = 0; let bytesSent = 0; let totalBytes = 0; 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(); alert("done"); } function sendData() { if (fileIndex >= files.length) { finishSending(); return; } const currentFile = files[fileIndex]; if (byteIndex < currentFile.size) { const endpoint = Math.min(byteIndex+FILE_CHUNK_SIZE, currentFile.size); const data = currentFile.slice(byteIndex, endpoint); socket.send(data); byteIndex = endpoint; bytesSent += data.size; progress.textContent = `${Math.floor(bytesSent * 100 / totalBytes)}%`; } else { fileIndex += 1; byteIndex = 0; sendData(); } } const fileInput = document.getElementById('file_input'); const fileInputMessage = document.getElementById('file_input_message'); const fileList = document.getElementById('file_list'); const uploadButton = document.getElementById('upload'); const downloadLink = document.getElementById('download_link'); const progress = document.getElementById('progress'); function updateButtons() { if (files.length === 0) { uploadButton.disabled = true; fileInputMessage.textContent = 'Select files to upload...'; } else { uploadButton.disabled = false; fileInputMessage.textContent = 'Select more files to upload...'; } } updateButtons(); function addFile(newFile) { if (files.some((oldFile) => newFile.name === oldFile.name)) { return; } files.push(newFile); const listEntry = document.createElement('li'); const deleteButton = document.createElement('button'); deleteButton.textContent = 'x'; deleteButton.addEventListener('click', () => { removeFile(newFile.name); listEntry.remove(); updateButtons(); }); const entryName = document.createElement('span'); entryName.textContent = newFile.name; listEntry.appendChild(deleteButton); listEntry.appendChild(entryName); 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); } updateButtons(); e.target.value = ''; }); uploadButton.addEventListener('click', (e) => { if (files.length === 0) { return; } fileInput.disabled = true; for (const button of document.getElementsByTagName('button')) { button.disabled = true; } totalBytes = files.reduce((acc, file) => acc + file.size, 0); socket = new WebSocket(`${window.location.protocol === 'http:' ? 'ws' : 'wss'}://${window.location.host}/upload`); socket.addEventListener('open', sendMetadata); socket.addEventListener('message', (msg) => { if (bytesSent === 0 && msg.data.match(/^[A-Za-z0-9]+$/)) { downloadLink.textContent = `${window.location.origin}/download/${msg.data}`; sendData(); } else if (msg.data === 'ack') { sendData(); } }); })