display upload speed and ETA

main
xenofem 2022-05-23 19:59:05 -04:00
parent 8f00eb27e2
commit 8b5e9b76bb
2 changed files with 53 additions and 3 deletions

View File

@ -1,5 +1,7 @@
const FILE_CHUNK_SIZE = 16384;
const MAX_FILES = 256;
const SAMPLE_WINDOW = 100;
const STALL_THRESHOLD = 1;
let files = [];
@ -8,6 +10,7 @@ let fileIndex = 0;
let byteIndex = 0;
let bytesSent = 0;
let totalBytes = 0;
let timestamps = [];
let maxSize = null;
@ -156,6 +159,7 @@ function beginUpload() {
fileIndex = 0;
byteIndex = 0;
bytesSent = 0;
timestamps = [];
let websocketUrl = new URL('upload', window.location);
websocketUrl.protocol = (window.location.protocol === 'http:') ? 'ws:' : 'wss:';
@ -249,6 +253,16 @@ function sendData() {
socket.send(data);
byteIndex = endpoint;
bytesSent += data.size;
// It's ok if the monotonically increasing fields like
// percentage are updating super quickly, but it's awkward for
// rate and ETA
const now = Date.now() / 1000;
if (timestamps.length === 0 || now - timestamps.at(-1)[0] > 1) {
timestamps.push([now, bytesSent]);
if (timestamps.length > SAMPLE_WINDOW) { timestamps.shift(); }
}
updateProgress();
} else {
fileIndex += 1;
@ -264,7 +278,22 @@ function updateProgress() {
} else {
percentage = `${(bytesSent*100/totalBytes).toFixed(1)}%`;
}
progress.textContent = `${percentage} (${displaySize(bytesSent)}/${displaySize(totalBytes)})`;
let progressString = `${percentage} - ${displaySize(bytesSent)}/${displaySize(totalBytes)}`;
if (timestamps.length >= 2) {
const start = timestamps.at(0);
const end = timestamps.at(-1);
if (end[0] - start[0] > 0) {
const rate = (end[1] - start[1])/(end[0] - start[0]);
if (rate > STALL_THRESHOLD) {
// Use the value from timestamps rather than bytesSent to avoid awkward UI thrashing
const remaining = (totalBytes - end[1]) / rate;
progressString += ` - ${displaySize(rate)}/s - ${displayTime(remaining)} remaining`;
} else {
progressString += " - stalled";
}
}
}
progress.textContent = progressString;
progressBar.style.backgroundSize = percentage;
const fileEntries = Array.from(fileList.children);

View File

@ -1,14 +1,35 @@
const UNITS = [
const SIZE_UNITS = [
{ name: 'GB', size: Math.pow(10, 9) },
{ name: 'MB', size: Math.pow(10, 6) },
{ name: 'KB', size: Math.pow(10, 3) },
];
function displaySize(bytes) {
for (const unit of UNITS) {
for (const unit of SIZE_UNITS) {
if (bytes >= unit.size) {
return `${(bytes / unit.size).toFixed(1)}${unit.name}`;
}
}
return `${bytes}B`;
}
const TIME_UNITS = [
{ name: 'd', size: 86400 },
{ name: 'h', size: 3600 },
{ name: 'm', size: 60 },
{ name: 's', size: 1 },
];
function displayTime(seconds) {
let result = "";
for (const unit of TIME_UNITS) {
if (seconds >= unit.size || result !== "") {
result += `${Math.floor(seconds / unit.size)}${unit.name}`;
seconds = seconds % unit.size;
}
}
if (result === "") {
result = "0s";
}
return result;
}