mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-07-13 06:41:11 -05:00
Fetch timeout
This commit is contained in:
parent
ca35545f98
commit
4bf9908362
17
src/api/f.ts
17
src/api/f.ts
|
|
@ -3,6 +3,7 @@ import fetch from 'node-fetch';
|
|||
import createDebug from 'debug';
|
||||
import { ErrorResponse } from './util.js';
|
||||
import { version } from '../util/product.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debugS2s = createDebug('nxapi:api:s2s');
|
||||
const debugFlapg = createDebug('nxapi:api:flapg');
|
||||
|
|
@ -16,6 +17,7 @@ const debugZncaApi = createDebug('nxapi:api:znca-api');
|
|||
export async function getLoginHash(token: string, timestamp: string | number, useragent?: string) {
|
||||
debugS2s('Getting login hash');
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch('https://elifessler.com/s2s/api/gen2', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -26,7 +28,8 @@ export async function getLoginHash(token: string, timestamp: string | number, us
|
|||
naIdToken: token,
|
||||
timestamp: '' + timestamp,
|
||||
}).toString(),
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const data = await response.json() as LoginHashApiResponse | LoginHashApiError;
|
||||
|
||||
|
|
@ -56,6 +59,7 @@ export async function flapg(
|
|||
token, timestamp, guid, iid,
|
||||
});
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch('https://flapg.com/ika2/api/login?public', {
|
||||
headers: {
|
||||
'User-Agent': (useragent ? useragent + ' ' : '') + 'nxapi/' + version,
|
||||
|
|
@ -66,7 +70,8 @@ export async function flapg(
|
|||
'x-ver': '3',
|
||||
'x-iid': iid,
|
||||
},
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const data = await response.json() as FlapgApiResponse;
|
||||
|
||||
|
|
@ -110,6 +115,7 @@ export async function iminkf(
|
|||
request_id: uuid,
|
||||
};
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch('https://api.imink.app/f', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -117,7 +123,8 @@ export async function iminkf(
|
|||
'User-Agent': (useragent ? useragent + ' ' : '') + 'nxapi/' + version,
|
||||
},
|
||||
body: JSON.stringify(req),
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const data = await response.json() as IminkFResponse | IminkFError;
|
||||
|
||||
|
|
@ -163,6 +170,7 @@ export async function genf(
|
|||
uuid,
|
||||
};
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -170,7 +178,8 @@ export async function genf(
|
|||
'User-Agent': (useragent ? useragent + ' ' : '') + 'nxapi/' + version,
|
||||
},
|
||||
body: JSON.stringify(req),
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const data = await response.json() as AndroidZncaFResponse | AndroidZncaFError;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import createDebug from 'debug';
|
|||
import { getNintendoAccountToken, getNintendoAccountUser } from './na.js';
|
||||
import { ErrorResponse } from './util.js';
|
||||
import { DailySummaries, Devices, MonthlySummaries, MonthlySummary, MoonError, ParentalControlSettingState, SmartDevices, User } from './moon-types.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:api:moon');
|
||||
|
||||
|
|
@ -19,8 +20,9 @@ export default class MoonApi {
|
|||
) {}
|
||||
|
||||
async fetch<T = unknown>(url: string, method = 'GET', body?: string, headers?: object) {
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(MOON_URL + url, {
|
||||
method: method,
|
||||
method,
|
||||
headers: Object.assign({
|
||||
'Authorization': 'Bearer ' + this.token,
|
||||
'Cache-Control': 'no-store',
|
||||
|
|
@ -37,8 +39,9 @@ export default class MoonApi {
|
|||
'User-Agent': 'moon_ANDROID/' + ZNMA_VERSION + ' (com.nintendo.znma; build:' + ZNMA_BUILD +
|
||||
'; ANDROID 26)',
|
||||
}, headers),
|
||||
body: body,
|
||||
});
|
||||
body,
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ import fetch from 'node-fetch';
|
|||
import createDebug from 'debug';
|
||||
import { ErrorResponse } from './util.js';
|
||||
import { JwtPayload } from '../util/jwt.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:api:na');
|
||||
|
||||
export async function getNintendoAccountSessionToken(code: string, verifier: string, client_id: string) {
|
||||
debug('Getting Nintendo Account session token');
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch('https://accounts.nintendo.com/connect/1.0.0/api/session_token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -21,7 +23,8 @@ export async function getNintendoAccountSessionToken(code: string, verifier: str
|
|||
session_token_code: code,
|
||||
session_token_code_verifier: verifier,
|
||||
}).toString(),
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const token = await response.json() as NintendoAccountSessionToken | NintendoAccountError;
|
||||
|
||||
|
|
@ -37,6 +40,7 @@ export async function getNintendoAccountSessionToken(code: string, verifier: str
|
|||
export async function getNintendoAccountToken(token: string, client_id: string) {
|
||||
debug('Getting Nintendo Account token');
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch('https://accounts.nintendo.com/connect/1.0.0/api/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -49,7 +53,8 @@ export async function getNintendoAccountToken(token: string, client_id: string)
|
|||
session_token: token,
|
||||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer-session-token',
|
||||
}),
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const nintendoAccountToken = await response.json() as NintendoAccountToken | NintendoAccountError;
|
||||
|
||||
|
|
@ -65,6 +70,7 @@ export async function getNintendoAccountToken(token: string, client_id: string)
|
|||
export async function getNintendoAccountUser(token: NintendoAccountToken) {
|
||||
debug('Getting Nintendo Account user info');
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch('https://api.accounts.nintendo.com/2.0.0/users/me', {
|
||||
headers: {
|
||||
'Accept-Language': 'en-GB',
|
||||
|
|
@ -73,7 +79,8 @@ export async function getNintendoAccountUser(token: NintendoAccountToken) {
|
|||
'Accept': 'application/json',
|
||||
'Authorization': 'Bearer ' + token.access_token!,
|
||||
},
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
const user = await response.json() as NintendoAccountUser | NintendoAccountError;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { NintendoAccountUser } from './na.js';
|
|||
import { ErrorResponse } from './util.js';
|
||||
import ZncApi from './znc.js';
|
||||
import { WebServiceError, Users, AuthToken, UserProfile, Newspapers, Newspaper, Emoticons, Reaction, IslandProfile } from './nooklink-types.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:api:nooklink');
|
||||
|
||||
|
|
@ -22,8 +23,9 @@ export default class NooklinkApi {
|
|||
) {}
|
||||
|
||||
async fetch<T = unknown>(url: string, method = 'GET', body?: string | FormData, headers?: object) {
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(NOOKLINK_URL + url, {
|
||||
method: method,
|
||||
method,
|
||||
headers: Object.assign({
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent': this.useragent,
|
||||
|
|
@ -36,8 +38,9 @@ export default class NooklinkApi {
|
|||
'Content-Type': 'application/json',
|
||||
'X-Blanco-Version': BLANCO_VERSION,
|
||||
}, headers),
|
||||
body: body,
|
||||
});
|
||||
body,
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
|
|
@ -96,6 +99,7 @@ export default class NooklinkApi {
|
|||
na_lang: user.language,
|
||||
}).toString();
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(url.toString(), {
|
||||
headers: {
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
|
|
@ -106,7 +110,8 @@ export default class NooklinkApi {
|
|||
'Accept-Language': 'en-GB,en-US;q=0.8',
|
||||
'X-Requested-With': 'com.nintendo.znca',
|
||||
},
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', 'GET', url, response.status);
|
||||
|
||||
|
|
@ -154,8 +159,9 @@ export class NooklinkUserApi {
|
|||
) {}
|
||||
|
||||
async fetch<T = unknown>(url: string, method = 'GET', body?: string | FormData, headers?: object) {
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(NOOKLINK_URL + url, {
|
||||
method: method,
|
||||
method,
|
||||
headers: Object.assign({
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent': this.useragent,
|
||||
|
|
@ -169,8 +175,9 @@ export class NooklinkUserApi {
|
|||
'Authorization': 'Bearer ' + this.auth_token,
|
||||
'X-Blanco-Version': BLANCO_VERSION,
|
||||
}, headers),
|
||||
body: body,
|
||||
});
|
||||
body,
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { NintendoAccountUser } from './na.js';
|
|||
import { ErrorResponse } from './util.js';
|
||||
import ZncApi from './znc.js';
|
||||
import { ActiveFestivals, CoopResult, CoopResults, CoopSchedules, HeroRecords, NicknameAndIcons, PastFestivals, Records, Result, Results, Schedules, ShareResponse, ShopMerchandises, Stages, Timeline, WebServiceError, XPowerRankingSummary } from './splatnet2-types.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:api:splatnet2');
|
||||
|
||||
|
|
@ -29,8 +30,9 @@ export default class SplatNet2Api {
|
|||
) {}
|
||||
|
||||
async fetch<T = unknown>(url: string, method = 'GET', body?: string | FormData, headers?: object) {
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(SPLATNET2_URL + url, {
|
||||
method: method,
|
||||
method,
|
||||
headers: Object.assign({
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent': this.useragent,
|
||||
|
|
@ -40,8 +42,9 @@ export default class SplatNet2Api {
|
|||
'Accept-Language': 'en-GB,en-US;q=0.8',
|
||||
'X-Requested-With': 'com.nintendo.znca',
|
||||
}, headers),
|
||||
body: body,
|
||||
});
|
||||
body,
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
|
|
@ -230,6 +233,7 @@ ${colour}
|
|||
na_lang: user.language,
|
||||
}).toString();
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(url.toString(), {
|
||||
headers: {
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
|
|
@ -240,7 +244,8 @@ ${colour}
|
|||
'Accept-Language': 'en-GB,en-US;q=0.8',
|
||||
'X-Requested-With': 'com.nintendo.znca',
|
||||
},
|
||||
});
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', 'GET', url, response.status);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import ZncApi from './znc.js';
|
|||
import { version } from '../util/product.js';
|
||||
import { NintendoAccountUser } from './na.js';
|
||||
import { SavedToken } from '../common/auth/nso.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:api:znc-proxy');
|
||||
|
||||
|
|
@ -26,14 +27,16 @@ export default class ZncProxyApi implements ZncApi {
|
|||
) {}
|
||||
|
||||
async fetch<T = unknown>(url: string, method = 'GET', body?: string, headers?: object) {
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(this.url + url, {
|
||||
method: method,
|
||||
method,
|
||||
headers: Object.assign({
|
||||
'Authorization': 'na ' + this.token,
|
||||
'User-Agent': (this.useragent ? this.useragent + ' ' : '') + 'nxapi/' + version,
|
||||
}, headers),
|
||||
body: body,
|
||||
});
|
||||
body,
|
||||
signal,
|
||||
}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
|
|
@ -178,7 +181,8 @@ export type PresenceUrlResponse =
|
|||
Friend | {friend: Friend};
|
||||
|
||||
export async function getPresenceFromUrl(presence_url: string) {
|
||||
const response = await fetch(presence_url);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(presence_url, {signal}).finally(cancel);
|
||||
|
||||
debug('fetch %s %s, response %s', 'GET', presence_url, response.status);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import createDebug from 'debug';
|
|||
import fetch from 'node-fetch';
|
||||
import SplatNet2Api, { ShareColour } from '../../api/splatnet2.js';
|
||||
import { Challenge, NicknameAndIcon, Records, Stages } from '../../api/splatnet2-types.js';
|
||||
import { timeoutSignal } from '../../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:splatnet2:dump-records');
|
||||
|
||||
|
|
@ -98,10 +99,6 @@ export async function dumpProfileImage(
|
|||
debug('Fetching profile image URL');
|
||||
const share = await splatnet.shareProfile(stage?.id ?? stages.stages[0].id, favourite_colour as ShareColour);
|
||||
|
||||
debug('Fetching profile image');
|
||||
const image_response = await fetch(share.url);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing profile image data %s', filename);
|
||||
await fs.writeFile(file, JSON.stringify({
|
||||
share,
|
||||
|
|
@ -109,6 +106,11 @@ export async function dumpProfileImage(
|
|||
colour: favourite_colour,
|
||||
}, null, 4) + '\n', 'utf-8');
|
||||
|
||||
debug('Fetching profile image', share);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const image_response = await fetch(share.url, {signal}).finally(cancel);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing profile image %s', image_filename);
|
||||
await fs.writeFile(image_file, Buffer.from(image));
|
||||
|
||||
|
|
@ -135,13 +137,14 @@ export async function dumpChallenges(
|
|||
debug('Fetching challenge image URL for %s', challenge.key);
|
||||
const share = await splatnet.shareChallenge(challenge.key, season);
|
||||
|
||||
debug('Fetching challenge image for %s', challenge.key);
|
||||
const image_response = await fetch(share.url);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing challenge image data %s', filename);
|
||||
await fs.writeFile(file, JSON.stringify({share}, null, 4) + '\n', 'utf-8');
|
||||
|
||||
debug('Fetching challenge image for %s', challenge.key, share);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const image_response = await fetch(share.url, {signal}).finally(cancel);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing challenge image %s', filename);
|
||||
await fs.writeFile(image_file, Buffer.from(image));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import createDebug from 'debug';
|
|||
import fetch from 'node-fetch';
|
||||
import SplatNet2Api from '../../api/splatnet2.js';
|
||||
import { NicknameAndIcon } from '../../api/splatnet2-types.js';
|
||||
import { timeoutSignal } from '../../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:splatnet2:dump-results');
|
||||
|
||||
|
|
@ -45,15 +46,16 @@ export async function dumpResults(
|
|||
debug('Fetching battle results summary image URL');
|
||||
const share = await splatnet.shareResultsSummary();
|
||||
|
||||
debug('Fetching battle results summary image');
|
||||
const image_response = await fetch(share.url);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing battle results summary image data %s', filename);
|
||||
await fs.writeFile(file, JSON.stringify({
|
||||
share,
|
||||
}, null, 4) + '\n', 'utf-8');
|
||||
|
||||
debug('Fetching battle results summary image', share);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const image_response = await fetch(share.url, {signal}).finally(cancel);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing battle results summary image %s', filename);
|
||||
await fs.writeFile(image_file, Buffer.from(image));
|
||||
}
|
||||
|
|
@ -102,15 +104,16 @@ export async function dumpResults(
|
|||
debug('Fetching battle results image URL');
|
||||
const share = await splatnet.shareResult(item.battle_number);
|
||||
|
||||
debug('Fetching battle results image');
|
||||
const image_response = await fetch(share.url);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing battle results image data %s', filename);
|
||||
await fs.writeFile(file, JSON.stringify({
|
||||
share,
|
||||
}, null, 4) + '\n', 'utf-8');
|
||||
|
||||
debug('Fetching battle results image', share);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const image_response = await fetch(share.url, {signal}).finally(cancel);
|
||||
const image = await image_response.arrayBuffer();
|
||||
|
||||
debug('Writing battle results image %s', filename);
|
||||
await fs.writeFile(image_file, Buffer.from(image));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import createDebug from 'debug';
|
|||
import mkdirp from 'mkdirp';
|
||||
import { dir, version } from '../util/product.js';
|
||||
import { paths } from '../util/storage.js';
|
||||
import { timeoutSignal } from '../util/misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:update');
|
||||
|
||||
|
|
@ -41,7 +42,8 @@ export async function checkUpdates() {
|
|||
debug('Checking for updates');
|
||||
|
||||
try {
|
||||
const response = await fetch(RELEASES_URL);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(RELEASES_URL, {signal}).finally(cancel);
|
||||
const releases = await response.json() as Release[];
|
||||
|
||||
const current = releases.find(r => r.tag_name === 'v' + version);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Buffer } from 'node:buffer';
|
|||
import createDebug from 'debug';
|
||||
import persist from 'node-persist';
|
||||
import fetch from 'node-fetch';
|
||||
import { timeoutSignal } from './misc.js';
|
||||
|
||||
const debug = createDebug('nxapi:util:jwt');
|
||||
|
||||
|
|
@ -135,7 +136,8 @@ export async function getJwks(url: string, storage?: persist.LocalStorage) {
|
|||
if (!cached_keyset || cached_keyset.expires_at <= Date.now()) {
|
||||
debug('Downloading JSON Web Key Set from %s', url);
|
||||
|
||||
const response = await fetch(url);
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(url, {signal}).finally(cancel);
|
||||
|
||||
const jwks = await response.json() as Jwks;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,3 +18,13 @@ export function hrduration(duration: number, short = false) {
|
|||
return minutes + ' ' + minute_str + (minutes === 1 ? '' : 's');
|
||||
}
|
||||
}
|
||||
|
||||
export function timeoutSignal(ms = 10 * 1000) {
|
||||
const controller = new AbortController();
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
controller.abort(new Error('Timeout'));
|
||||
}, ms);
|
||||
|
||||
return [controller.signal, () => clearTimeout(timeout)] as const;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user