web-install: Show download progress
Getting progress with the fetch() API is complicated and requires us to stream the data and create the blob ourselves, so use XMLHttpRequest instead to get live progress updates.
This commit is contained in:
parent
cdafb40dd6
commit
d44bafb8cf
@ -163,7 +163,11 @@
|
||||
|
||||
<button id="download-release-button" disabled="disabled">Download release</button>
|
||||
|
||||
<p><strong id="download-release-status"></strong></p>
|
||||
<p id="download-release-status-container" hidden="hidden">
|
||||
<strong id="download-release-status"></strong>
|
||||
<br/>
|
||||
<progress id="download-release-progress" hidden="hidden" max="1" value="0"></progress>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="flashing-factory-images">
|
||||
|
@ -7,6 +7,26 @@ const RELEASES_URL = "https://releases.grapheneos.org";
|
||||
const CACHE_DB_NAME = "BlobStore";
|
||||
const CACHE_DB_VERSION = 1;
|
||||
|
||||
// This wraps XHR because getting progress updates with fetch() is overly complicated.
|
||||
function fetchBlobWithProgress(url, onProgress) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url);
|
||||
xhr.responseType = "blob";
|
||||
xhr.send();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
xhr.onload = () => {
|
||||
resolve(xhr.response);
|
||||
};
|
||||
xhr.onprogress = (event) => {
|
||||
onProgress(event.loaded / event.total);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
reject(`${xhr.status} ${xhr.statusText}`);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
class BlobStore {
|
||||
constructor() {
|
||||
this.db = null;
|
||||
@ -65,19 +85,12 @@ class BlobStore {
|
||||
this.db.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the file from the given URL and saves it to this BlobStore.
|
||||
*
|
||||
* @param {string} url - URL of the file to download.
|
||||
* @returns {blob} Blob containing the downloaded data.
|
||||
*/
|
||||
async download(url) {
|
||||
async download(url, onProgress = () => {}) {
|
||||
let filename = url.split("/").pop();
|
||||
let blob = await this.loadFile(filename);
|
||||
if (blob === null) {
|
||||
console.log(`Downloading ${url}`);
|
||||
let resp = await fetch(new Request(url));
|
||||
blob = await resp.blob();
|
||||
let blob = await fetchBlobWithProgress(url, onProgress);
|
||||
console.log("File downloaded, saving...");
|
||||
await this.saveFile(filename, blob);
|
||||
console.log("File saved");
|
||||
@ -144,8 +157,10 @@ async function downloadRelease(setProgress) {
|
||||
// Download and cache the zip as a blob
|
||||
setProgress(`Downloading ${latestZip}...`);
|
||||
await blobStore.init();
|
||||
await blobStore.download(`${RELEASES_URL}/${latestZip}`);
|
||||
return `Downloaded ${latestZip} release.`;
|
||||
await blobStore.download(`${RELEASES_URL}/${latestZip}`, (progress) => {
|
||||
setProgress(`Downloading ${latestZip}...`, progress);
|
||||
});
|
||||
setProgress(`Downloaded ${latestZip} release.`, 1.0);
|
||||
}
|
||||
|
||||
async function reconnectCallback() {
|
||||
@ -238,7 +253,9 @@ function addButtonHook(id, callback) {
|
||||
button.onclick = async () => {
|
||||
try {
|
||||
let finalStatus = await callback(statusCallback);
|
||||
statusCallback(finalStatus);
|
||||
if (finalStatus !== undefined) {
|
||||
statusCallback(finalStatus);
|
||||
}
|
||||
} catch (error) {
|
||||
statusCallback(`Error: ${error.message}`);
|
||||
statusField.className = "error-text";
|
||||
|
Loading…
x
Reference in New Issue
Block a user