display upload speed and ETA
This commit is contained in:
parent
8f00eb27e2
commit
8b5e9b76bb
|
@ -1,5 +1,7 @@
|
||||||
const FILE_CHUNK_SIZE = 16384;
|
const FILE_CHUNK_SIZE = 16384;
|
||||||
const MAX_FILES = 256;
|
const MAX_FILES = 256;
|
||||||
|
const SAMPLE_WINDOW = 100;
|
||||||
|
const STALL_THRESHOLD = 1;
|
||||||
|
|
||||||
let files = [];
|
let files = [];
|
||||||
|
|
||||||
|
@ -8,6 +10,7 @@ let fileIndex = 0;
|
||||||
let byteIndex = 0;
|
let byteIndex = 0;
|
||||||
let bytesSent = 0;
|
let bytesSent = 0;
|
||||||
let totalBytes = 0;
|
let totalBytes = 0;
|
||||||
|
let timestamps = [];
|
||||||
|
|
||||||
let maxSize = null;
|
let maxSize = null;
|
||||||
|
|
||||||
|
@ -156,6 +159,7 @@ function beginUpload() {
|
||||||
fileIndex = 0;
|
fileIndex = 0;
|
||||||
byteIndex = 0;
|
byteIndex = 0;
|
||||||
bytesSent = 0;
|
bytesSent = 0;
|
||||||
|
timestamps = [];
|
||||||
|
|
||||||
let websocketUrl = new URL('upload', window.location);
|
let websocketUrl = new URL('upload', window.location);
|
||||||
websocketUrl.protocol = (window.location.protocol === 'http:') ? 'ws:' : 'wss:';
|
websocketUrl.protocol = (window.location.protocol === 'http:') ? 'ws:' : 'wss:';
|
||||||
|
@ -249,6 +253,16 @@ function sendData() {
|
||||||
socket.send(data);
|
socket.send(data);
|
||||||
byteIndex = endpoint;
|
byteIndex = endpoint;
|
||||||
bytesSent += data.size;
|
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();
|
updateProgress();
|
||||||
} else {
|
} else {
|
||||||
fileIndex += 1;
|
fileIndex += 1;
|
||||||
|
@ -264,7 +278,22 @@ function updateProgress() {
|
||||||
} else {
|
} else {
|
||||||
percentage = `${(bytesSent*100/totalBytes).toFixed(1)}%`;
|
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;
|
progressBar.style.backgroundSize = percentage;
|
||||||
|
|
||||||
const fileEntries = Array.from(fileList.children);
|
const fileEntries = Array.from(fileList.children);
|
||||||
|
|
|
@ -1,14 +1,35 @@
|
||||||
const UNITS = [
|
const SIZE_UNITS = [
|
||||||
{ name: 'GB', size: Math.pow(10, 9) },
|
{ name: 'GB', size: Math.pow(10, 9) },
|
||||||
{ name: 'MB', size: Math.pow(10, 6) },
|
{ name: 'MB', size: Math.pow(10, 6) },
|
||||||
{ name: 'KB', size: Math.pow(10, 3) },
|
{ name: 'KB', size: Math.pow(10, 3) },
|
||||||
];
|
];
|
||||||
|
|
||||||
function displaySize(bytes) {
|
function displaySize(bytes) {
|
||||||
for (const unit of UNITS) {
|
for (const unit of SIZE_UNITS) {
|
||||||
if (bytes >= unit.size) {
|
if (bytes >= unit.size) {
|
||||||
return `${(bytes / unit.size).toFixed(1)}${unit.name}`;
|
return `${(bytes / unit.size).toFixed(1)}${unit.name}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `${bytes}B`;
|
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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue