Add blobs.turbowarp.xyz fallback when fetching large assets

similar situation to cloud variables
this should be more reliable in filtered environments
https://github.com/TurboWarp/desktop/discussions/355#discussioncomment-2448055
This commit is contained in:
Thomas Weber committed 2022-03-27 18:06:48 -05:00
1 parent 8576a34ba1
commit 6969a07f2a
3 files changed
+105 -73

No files matched your search

+78 -59
View File
@@ -1,71 +1,90 @@
const clampProgress = (n) => Math.max(0, Math.min(1, n));
const request = ({
url,
type,
progressCallback,
timeout,
estimatedSize,
abortTarget
}) => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = () => {
cleanup();
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(`Couldn't fetch ${url}: status code ${xhr.status}`));
}
};
xhr.onerror = () => {
cleanup();
reject(new Error(`Couldn't fetch ${url}, are you offline?`));
};
const request = async (options) => {
const {
type,
progressCallback,
timeout,
estimatedSize,
abortTarget
} = options;
if (progressCallback) {
xhr.onprogress = (e) => {
if (e.lengthComputable) {
progressCallback(clampProgress(e.loaded / e.total));
} else if (estimatedSize) {
progressCallback(clampProgress(e.loaded / estimatedSize));
const requestURL = (url) => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = () => {
cleanup();
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(`Couldn't fetch ${url}: status code ${xhr.status}`));
}
};
}
xhr.responseType = type;
xhr.open('GET', url);
xhr.send();
const cleanup = () => {
if (cleanupAbortCallback) {
cleanupAbortCallback();
}
if (timeoutId) {
clearTimeout(timeoutId);
}
};
let cleanupAbortCallback;
if (abortTarget) {
const abortCallback = () => {
xhr.abort();
xhr.onerror = () => {
cleanup();
reject(new Error(`Couldn't fetch ${url}: aborted`));
reject(new Error(`Couldn't fetch ${url}, are you offline?`));
};
abortTarget.addEventListener('abort', abortCallback);
cleanupAbortCallback = () => {
abortTarget.removeEventListener('abort', abortCallback);
if (progressCallback) {
xhr.onprogress = (e) => {
if (e.lengthComputable) {
progressCallback(clampProgress(e.loaded / e.total));
} else if (estimatedSize) {
progressCallback(clampProgress(e.loaded / estimatedSize));
}
};
}
xhr.responseType = type;
xhr.open('GET', url);
xhr.send();
const cleanup = () => {
if (cleanupAbortCallback) {
cleanupAbortCallback();
}
if (timeoutId) {
clearTimeout(timeoutId);
}
};
}
let cleanupAbortCallback;
if (abortTarget) {
const abortCallback = () => {
xhr.abort();
cleanup();
reject(new Error(`Couldn't fetch ${url}: aborted`));
};
abortTarget.addEventListener('abort', abortCallback);
cleanupAbortCallback = () => {
abortTarget.removeEventListener('abort', abortCallback);
};
}
let timeoutId;
if (timeout) {
timeoutId = setTimeout(() => {
xhr.abort();
cleanup();
reject(new Error(`Couldn't fetch ${url}: timed out`));
}, timeout);
}
});
let timeoutId;
if (timeout) {
timeoutId = setTimeout(() => {
xhr.abort();
cleanup();
reject(new Error(`Couldn't fetch ${url}: timed out`));
}, timeout);
const urls = Array.isArray(options.url) ? options.url : [options.url];
if (urls.length === 0) {
throw new Error('no URLs');
}
});
let errorToThrow;
for (const url of urls) {
try {
return await requestURL(url);
} catch (e) {
if (!errorToThrow) {
errorToThrow = e;
}
}
}
throw errorToThrow;
};
export default request;
+24 -13
View File
@@ -1,61 +1,72 @@
const LARGE_ASSET_BASE = 'https://packagerdata.turbowarp.org/';
const SCAFFOLDING_ROOT = 'scaffolding/';
// This defines where files are fetched from when the packager needs to download files.
// Files fetched from an external server have a SHA-256 checksum used to validate the download.
// src is the URL that will be fetched to download the asset. If it's an array of URLs, each URL
// will be tried in succession if the previous one fails, perhaps because it's blocked by a school
// network filter.
const externalFile = (name) => [
// Hopefully one of these URLs will not be blocked.
`https://packagerdata.turbowarp.org/${name}`,
`https://blobs.turbowarp.xyz/${name}`
];
const relativeScaffolding = (name) => `scaffolding/${name}`;
export default {
'nwjs-win64': {
src: LARGE_ASSET_BASE + 'nwjs-v0.54.0-win-x64.zip',
src: externalFile('nwjs-v0.54.0-win-x64.zip'),
sha256: '0f082671b67b711f783d98cc989cf5aebacfc9bce3bef78875b57d08fc2a6e86',
type: 'arraybuffer'
},
'nwjs-win32': {
src: LARGE_ASSET_BASE + 'nwjs-v0.54.0-win-ia32.zip',
src: externalFile('nwjs-v0.54.0-win-ia32.zip'),
sha256: '7a1ed3a6a51b8cdf9280761b90cb4723cf9ee8050e3ed0b58451e8e4e694b203',
type: 'arraybuffer'
},
'nwjs-mac': {
src: LARGE_ASSET_BASE + 'nwjs-v0.54.0-osx-x64.zip',
src: externalFile('nwjs-v0.54.0-osx-x64.zip'),
sha256: '498c97a264f8feac504c4c2396c1fddc8290c15573aee2fc692e59ff9803cc40',
type: 'arraybuffer'
},
'nwjs-linux-x64': {
src: LARGE_ASSET_BASE + 'nwjs-v0.54.0-linux-x64.zip',
src: externalFile('nwjs-v0.54.0-linux-x64.zip'),
sha256: '53651a3a12d29ad096cff5b44d9f1e3aa09e9fad970bdcfe8bda07ea23d960d8',
type: 'arraybuffer'
},
'electron-win32': {
src: LARGE_ASSET_BASE + 'electron-v15.0.0-win32-ia32.zip',
src: externalFile('electron-v15.0.0-win32-ia32.zip'),
sha256: '5b69112b91010d78abf6012f387ea3fe5c0e36657c5f386a4c2bb42138aa1a8e',
type: 'arraybuffer'
},
'electron-win64': {
src: LARGE_ASSET_BASE + 'electron-v15.0.0-win32-x64.zip',
src: externalFile('electron-v15.0.0-win32-x64.zip'),
sha256: '3d95422d9f2fccb07b745b31007548231d80ff63e3640f49a5f8591498a3afa2',
type: 'arraybuffer'
},
'electron-linux64': {
src: LARGE_ASSET_BASE + 'electron-v15.1.1-linux-x64.zip',
src: externalFile('electron-v15.1.1-linux-x64.zip'),
sha256: '70de2da51c6a8591b88f08366c82166a51b1719243f67ef1a14eddbb806a115f',
type: 'arraybuffer'
},
'webview-mac': {
src: LARGE_ASSET_BASE + 'WebView-macos-3.zip',
src: externalFile('WebView-macos-3.zip'),
sha256: '5d4086894f10549c61c20e5f770c808afc25c2e4793da75b5b1cede294449fac',
type: 'arraybuffer'
},
scaffolding: {
src: SCAFFOLDING_ROOT + 'scaffolding.js',
src: relativeScaffolding('scaffolding.js'),
estimatedSize: 4775503,
useBuildId: true,
type: 'text'
},
'scaffolding-min': {
src: SCAFFOLDING_ROOT + 'scaffolding-min.js',
src: relativeScaffolding('scaffolding-min.js'),
estimatedSize: 2540321,
useBuildId: true,
type: 'text'
},
addons: {
src: SCAFFOLDING_ROOT + 'addons.js',
src: relativeScaffolding('addons.js'),
estimatedSize: 14339,
useBuildId: true,
type: 'text'
+3 -1
View File
@@ -9,7 +9,9 @@ const STORE_NAME = 'assets';
const db = new Database(DATABASE_NAME, DATABASE_VERSION, STORE_NAME);
const getAssetId = (asset) => {
return `${asset.src}-${asset.type}-${asset.sha256 || buildId}`;
const urls = asset.src;
const firstURL = Array.isArray(urls) ? urls[0] : urls;
return `${firstURL}-${asset.type}-${asset.sha256 || buildId}`;
};
const removeExtraneous = async () => {