From f110df1206540d30decf1acf138b7a44acd502ba Mon Sep 17 00:00:00 2001 From: sunnylqm Date: Tue, 28 Jul 2020 23:15:42 +0800 Subject: [PATCH] Add custom endpoints --- endpoints.json | 1 + lib/endpoint.js | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/getHost.js | 57 ---------------------------------- lib/index.d.ts | 18 ++++++++--- lib/index.js | 12 +++----- 5 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 endpoints.json create mode 100644 lib/endpoint.js delete mode 100644 lib/getHost.js diff --git a/endpoints.json b/endpoints.json new file mode 100644 index 0000000..c1e7e3e --- /dev/null +++ b/endpoints.json @@ -0,0 +1 @@ +["https://update.react-native.cn/api", "https://update.reactnative.cn/api"] diff --git a/lib/endpoint.js b/lib/endpoint.js new file mode 100644 index 0000000..f298ef0 --- /dev/null +++ b/lib/endpoint.js @@ -0,0 +1,82 @@ +let currentEndpoint = 'https://update.reactnative.cn/api'; + +function ping(url, rejectImmediate) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.onreadystatechange = (e) => { + if (xhr.readyState !== 4) { + return; + } + if (xhr.status === 200) { + resolve(url); + } else { + rejectImmediate ? reject() : setTimeout(reject, 5000); + } + }; + xhr.open('HEAD', url); + xhr.send(); + xhr.timeout = 5000; + xhr.ontimeout = reject; + }); +} + +function logger(...args) { + // console.warn('pushy', ...args); +} + +let backupEndpoints = []; +let backupEndpointsQueryUrl = + 'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/endpoints.json'; + +export async function tryBackupEndpoints() { + try { + await ping(getStatusUrl(), true); + logger('current endpoint ok'); + return; + } catch (e) { + logger('current endpoint failed'); + } + if (!backupEndpoints.length && backupEndpointsQueryUrl) { + try { + const resp = await fetch(backupEndpointsQueryUrl); + backupEndpoints = await resp.json(); + logger('get remote endpoints:', backupEndpoints); + } catch (e) { + logger('get remote endpoints failed'); + return; + } + } + await pickFatestAvailableEndpoint(); +} + +async function pickFatestAvailableEndpoint(endpoints = backupEndpoints) { + const fastestEndpoint = await Promise.race( + endpoints.map(pingAndReturnEndpoint), + ); + if (typeof fastestEndpoint === 'string') { + logger(`pick endpoint: ${fastestEndpoint}`); + currentEndpoint = fastestEndpoint; + } else { + logger('all remote endpoints failed'); + } +} + +async function pingAndReturnEndpoint(endpoint = currentEndpoint) { + return ping(getStatusUrl(endpoint)).then(() => endpoint); +} + +function getStatusUrl(endpoint = currentEndpoint) { + return `${endpoint}/status`; +} + +export function getCheckUrl(APPKEY, endpoint = currentEndpoint) { + return `${endpoint}/checkUpdate/${APPKEY}`; +} + +export function setCustomEndpoints(mainEndpoint, backups) { + currentEndpoint = mainEndpoint; + if (Array.isArray(backups) && backups.length > 0) { + backupEndpoints = backups; + pickFatestAvailableEndpoint(); + } +} diff --git a/lib/getHost.js b/lib/getHost.js deleted file mode 100644 index b0a46aa..0000000 --- a/lib/getHost.js +++ /dev/null @@ -1,57 +0,0 @@ -let availableDomain = 'update.react-native.cn'; - -function ping(domain, rejectImmediate) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.onreadystatechange = e => { - if (xhr.readyState !== 4) { - return; - } - if (xhr.status === 200) { - resolve(domain); - } else { - rejectImmediate ? reject() : setTimeout(reject, 5000); - } - }; - xhr.open('HEAD', `https://${domain}`); - xhr.send(); - xhr.timeout = 5000; - xhr.ontimeout = reject; - }); -} - -function logger(...args) { - // console.warn('pushy', ...args); -} - -export async function tryBackupDomains() { - try { - await ping(availableDomain, true); - logger('main domain ok'); - return; - } catch (e) { - logger('main domain failed'); - } - let backupDomains = []; - try { - const resp = await fetch( - 'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/domains.json', - ); - backupDomains = await resp.json(); - logger('get remote domains:', backupDomains); - } catch (e) { - logger('get remote domains failed'); - return; - } - const fastestDomain = await Promise.race(backupDomains.map(ping)); - if (typeof fastestDomain === 'string') { - logger(`pick domain: ${fastestDomain}`); - availableDomain = fastestDomain; - } else { - logger('all remote domains failed'); - } -} - -export default function getHost() { - return `https://${availableDomain}/api`; -} diff --git a/lib/index.d.ts b/lib/index.d.ts index 0f7ff6c..731ebd8 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -20,17 +20,27 @@ export interface UpdateAvailableResult { description: string; metaInfo: string; pdiffUrl: string; - diffUrl: string; -} + diffUrl?: string; +}; -export type CheckResult = Partial; +export type CheckResult = + | ExpiredResult + | UpTodateResult + | UpdateAvailableResult; export function checkUpdate(appkey: string): Promise; -export function downloadUpdate(options: UpdateAvailableResult): Promise; +export function downloadUpdate( + options: UpdateAvailableResult, +): Promise; export function switchVersion(hash: string): void; export function switchVersionLater(hash: string): void; export function markSuccess(): void; + +export function setCustomEndpoints( + mainEndpoint: string, + backupEndpoints?: string[], +): void; diff --git a/lib/index.js b/lib/index.js index 06d287d..05e952c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,6 @@ -import getHost, { tryBackupDomains } from './getHost'; +import { tryBackupEndpoints, getCheckUrl, setCustomEndpoints } from './endpoint'; import { NativeAppEventEmitter, NativeModules } from 'react-native'; +export { setCustomEndpoints }; let Pushy = NativeModules.Pushy; @@ -47,7 +48,7 @@ export async function checkUpdate(APPKEY, isRetry) { assertRelease(); let resp; try { - resp = await fetch(`${getHost()}/checkUpdate/${APPKEY}`, { + resp = await fetch(getCheckUrl(APPKEY), { method: 'POST', headers: { Accept: 'application/json', @@ -63,7 +64,7 @@ export async function checkUpdate(APPKEY, isRetry) { if (isRetry) { throw new Error('Could not connect to pushy server'); } - await tryBackupDomains(); + await tryBackupEndpoints(APPKEY); return checkUpdate(APPKEY, true); } @@ -91,11 +92,6 @@ export async function downloadUpdate(options) { updateUrl: options.pdiffUrl, hashName: options.hash, }); - } else { - await Pushy.downloadUpdate({ - updateUrl: options.updateUrl, - hashName: options.hash, - }); } return options.hash; }