This commit is contained in:
2025-01-04 00:34:03 +01:00
parent 41829408dc
commit 0ca14bbc19
18111 changed files with 1871397 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
/**
* A wrapper method around `fetch` that attaches an AbortController signal to the `fetch` call for clean timeouts
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#aborting_a_fetch_with_timeout_or_explicit_abort
* @param {string} url The URL to make the Request to
* @param {Object} data The data of the Request
* @param {number|null} timeoutMs How long to wait for a Response before cleanly aborting.
* If null, no timeout is applied
* @param {function} onTimeout A method to invoke if and when the timeout is reached
* @return {Promise<Response>}
* @throws {HttpError}
*/
export async function fetchWithTimeout(url, data = {}, {timeoutMs=30000, onTimeout = () => {}} = {}) {
const controller = new AbortController();
data.signal = controller.signal;
let timedOut = false;
const enforceTimeout = timeoutMs !== null;
// Enforce a timeout
let timeout;
if ( enforceTimeout ) {
timeout = setTimeout(() => {
timedOut = true;
controller.abort();
onTimeout();
}, timeoutMs);
}
// Attempt the request
let response;
try {
response = await fetch(url, data);
} catch(err) {
if ( timedOut ) {
const timeoutS = Math.round(timeoutMs / 1000);
const msg = game.i18n
? game.i18n.format("SETUP.ErrorTimeout", { url, timeout: timeoutS })
: `The request to ${url} timed out after ${timeoutS}s.`;
throw new HttpError("Timed Out", 408, msg);
}
throw err;
} finally {
if ( enforceTimeout ) clearTimeout(timeout);
}
// Return the response
if ( !response.ok && (response.type !== "opaqueredirect") ) {
const responseBody = response.body ? await response.text() : "";
throw new HttpError(response.statusText, response.status, responseBody);
}
return response;
}
/* ----------------------------------------- */
/**
* A small wrapper that automatically asks for JSON with a Timeout
* @param {string} url The URL to make the Request to
* @param {Object} data The data of the Request
* @param {int} timeoutMs How long to wait for a Response before cleanly aborting
* @param {function} onTimeout A method to invoke if and when the timeout is reached
* @returns {Promise<*>}
*/
export async function fetchJsonWithTimeout(url, data = {}, {timeoutMs=30000, onTimeout = () => {}} = {}) {
let response = await fetchWithTimeout(url, data, {timeoutMs: timeoutMs, onTimeout: onTimeout});
return response.json();
}
/* ----------------------------------------- */
/**
* Represents an HTTP Error when a non-OK response is returned by Fetch
* @extends {Error}
*/
export class HttpError extends Error {
constructor(statusText, code, displayMessage="") {
super(statusText);
this.code = code;
this.displayMessage = displayMessage;
}
/* -------------------------------------------- */
/** @override */
toString() {
return this.displayMessage;
}
}