This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.8 KiB
115 lines
3.8 KiB
/** |
|
* Copyright (c) 2013-present, Facebook, Inc. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
* |
|
* @providesModule fetchWithRetries |
|
* @typechecks |
|
* @flow |
|
*/ |
|
|
|
'use strict'; |
|
|
|
const ExecutionEnvironment = require('./ExecutionEnvironment'); |
|
|
|
const sprintf = require('./sprintf'); |
|
const fetch = require('./fetch'); |
|
const warning = require('./warning'); |
|
|
|
export type InitWithRetries = { |
|
body?: mixed; |
|
cache?: ?string; |
|
credentials?: ?string; |
|
fetchTimeout?: ?number; |
|
headers?: mixed; |
|
method?: ?string; |
|
mode?: ?string; |
|
retryDelays?: ?Array<number>; |
|
}; |
|
|
|
const DEFAULT_TIMEOUT = 15000; |
|
const DEFAULT_RETRIES = [1000, 3000]; |
|
|
|
/** |
|
* Makes a POST request to the server with the given data as the payload. |
|
* Automatic retries are done based on the values in `retryDelays`. |
|
*/ |
|
function fetchWithRetries(uri: string, initWithRetries?: ?InitWithRetries): Promise<any> { |
|
const { fetchTimeout, retryDelays, ...init } = initWithRetries || {}; |
|
const _fetchTimeout = fetchTimeout != null ? fetchTimeout : DEFAULT_TIMEOUT; |
|
const _retryDelays = retryDelays != null ? retryDelays : DEFAULT_RETRIES; |
|
|
|
let requestsAttempted = 0; |
|
let requestStartTime = 0; |
|
return new Promise((resolve, reject) => { |
|
/** |
|
* Sends a request to the server that will timeout after `fetchTimeout`. |
|
* If the request fails or times out a new request might be scheduled. |
|
*/ |
|
function sendTimedRequest(): void { |
|
requestsAttempted++; |
|
requestStartTime = Date.now(); |
|
let isRequestAlive = true; |
|
const request = fetch(uri, init); |
|
const requestTimeout = setTimeout(() => { |
|
isRequestAlive = false; |
|
if (shouldRetry(requestsAttempted)) { |
|
warning(false, 'fetchWithRetries: HTTP timeout, retrying.'); |
|
retryRequest(); |
|
} else { |
|
reject(new Error(sprintf('fetchWithRetries(): Failed to get response from server, ' + 'tried %s times.', requestsAttempted))); |
|
} |
|
}, _fetchTimeout); |
|
|
|
request.then(response => { |
|
clearTimeout(requestTimeout); |
|
if (isRequestAlive) { |
|
// We got a response, we can clear the timeout. |
|
if (response.status >= 200 && response.status < 300) { |
|
// Got a response code that indicates success, resolve the promise. |
|
resolve(response); |
|
} else if (shouldRetry(requestsAttempted)) { |
|
// Fetch was not successful, retrying. |
|
// TODO(#7595849): Only retry on transient HTTP errors. |
|
warning(false, 'fetchWithRetries: HTTP error, retrying.'), retryRequest(); |
|
} else { |
|
// Request was not successful, giving up. |
|
const error: any = new Error(sprintf('fetchWithRetries(): Still no successful response after ' + '%s retries, giving up.', requestsAttempted)); |
|
error.response = response; |
|
reject(error); |
|
} |
|
} |
|
}).catch(error => { |
|
clearTimeout(requestTimeout); |
|
if (shouldRetry(requestsAttempted)) { |
|
retryRequest(); |
|
} else { |
|
reject(error); |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* Schedules another run of sendTimedRequest based on how much time has |
|
* passed between the time the last request was sent and now. |
|
*/ |
|
function retryRequest(): void { |
|
const retryDelay = _retryDelays[requestsAttempted - 1]; |
|
const retryStartTime = requestStartTime + retryDelay; |
|
// Schedule retry for a configured duration after last request started. |
|
setTimeout(sendTimedRequest, retryStartTime - Date.now()); |
|
} |
|
|
|
/** |
|
* Checks if another attempt should be done to send a request to the server. |
|
*/ |
|
function shouldRetry(attempt: number): boolean { |
|
return ExecutionEnvironment.canUseDOM && attempt <= _retryDelays.length; |
|
} |
|
|
|
sendTimedRequest(); |
|
}); |
|
} |
|
|
|
module.exports = fetchWithRetries; |