Skip to content

Commit

Permalink
fix(api): add ETIMEDOUT handling to Twitch API calls
Browse files Browse the repository at this point in the history
  • Loading branch information
sogehige committed Oct 13, 2022
1 parent a021e61 commit d050596
Show file tree
Hide file tree
Showing 24 changed files with 142 additions and 14 deletions.
4 changes: 4 additions & 0 deletions src/services/twitch/calls/checkClips.ts
Expand Up @@ -33,6 +33,10 @@ export async function checkClips () {
}
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/createClip.ts
Expand Up @@ -47,6 +47,10 @@ export async function createClip (opts: { createAfterDelay: boolean }) {
return (await isClipChecked(clipId)) ? clipId : null;
} catch (e: unknown) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
9 changes: 8 additions & 1 deletion src/services/twitch/calls/createMarker.ts
Expand Up @@ -4,8 +4,10 @@ import { refresh } from '../token/refresh.js';

import { getFunctionName } from '~/helpers/getFunctionName';
import { variables } from '~/watchers';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';
import { HelixStreamMarker } from '@twurple/api/lib';

export async function createMarker (description = 'Marked from sogeBot') {
export async function createMarker (description = 'Marked from sogeBot'): Promise<HelixStreamMarker | void> {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand All @@ -16,6 +18,11 @@ export async function createMarker (description = 'Marked from sogeBot') {
clientBot.streams.createStreamMarker(broadcasterId, description);
} catch (e: unknown) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return createMarker(description);
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getAllStreamTags.ts
Expand Up @@ -44,6 +44,10 @@ export async function getAllStreamTags(opts: any) {
await getRepository(TwitchTagLocalizationName).delete({ tagId: IsNull() });
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false, opts }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getChannelChatBadges.ts
Expand Up @@ -23,6 +23,10 @@ export async function getChannelChatBadges() {
];
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('broadcaster');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getChannelChattersUnofficialAPI.ts
Expand Up @@ -116,6 +116,10 @@ export const getChannelChattersUnofficialAPI = async (opts: any) => {
}
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false, opts }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getChannelInformation.ts
Expand Up @@ -74,6 +74,10 @@ export async function getChannelInformation (opts: any) {
}
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false, opts }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getChannelSubscribers.ts
Expand Up @@ -46,6 +46,10 @@ export async function getChannelSubscribers<T extends { noAffiliateOrPartnerWarn
opts.notCorrectOauthWarningSent = false;
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false, opts }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getCurrentStream.ts
Expand Up @@ -75,6 +75,10 @@ export async function getCurrentStream (opts: any) {
}
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false, opts }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getCurrentStreamTags.ts
Expand Up @@ -24,6 +24,10 @@ export async function getCurrentStreamTags (opts: any) {
}
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false, opts }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
10 changes: 9 additions & 1 deletion src/services/twitch/calls/getCustomRewards.ts
Expand Up @@ -4,8 +4,10 @@ import { refresh } from '../token/refresh.js';
import { getFunctionName } from '~/helpers/getFunctionName';
import { debug, error, isDebugEnabled, warning } from '~/helpers/log';
import { variables } from '~/watchers';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';
import { HelixCustomReward } from '@twurple/api/lib';

export const getCustomRewards = async () => {
export const getCustomRewards = async (): Promise<HelixCustomReward[]> => {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand All @@ -15,12 +17,18 @@ export const getCustomRewards = async () => {
return await clientBroadcaster.channelPoints.getCustomRewards(broadcasterId);
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return getCustomRewards();
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
} else {
error(`${getFunctionName()} => ${e.stack ?? e.message}`);
}
}
return [];
}
};
9 changes: 8 additions & 1 deletion src/services/twitch/calls/getGameIdFromName.ts
Expand Up @@ -5,6 +5,7 @@ import client from '../api/client';

import { stats } from '~/helpers/api';
import { debug, isDebugEnabled, warning } from '~/helpers/log';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

async function getGameIdFromName (name: string): Promise<string | undefined> {
if (isDebugEnabled('api.calls')) {
Expand All @@ -28,7 +29,13 @@ async function getGameIdFromName (name: string): Promise<string | undefined> {
return String(id);
} catch (e: unknown) {
if (e instanceof Error) {
warning(`getGameIdFromName => ${e.stack ?? e.message}`);
if (e.message.includes('ETIMEDOUT')) {
warning(`getGameIdFromName => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return getGameIdFromName(name);
} else {
warning(`getGameIdFromName => ${e.stack ?? e.message}`);
}
}
return undefined;
}
Expand Down
13 changes: 10 additions & 3 deletions src/services/twitch/calls/getGameNameFromId.ts
Expand Up @@ -5,8 +5,9 @@ import client from '../api/client';

import { stats } from '~/helpers/api';
import { debug, isDebugEnabled, warning } from '~/helpers/log';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

async function getGameNameFromId (id: number) {
async function getGameNameFromId (id: number): Promise<string> {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand All @@ -31,9 +32,15 @@ async function getGameNameFromId (id: number) {
return getGameById.name;
} catch (e: unknown) {
if (e instanceof Error) {
warning(`getGameNameFromId => ${e.stack ?? e.message}`);
if (e.message.includes('ETIMEDOUT')) {
warning(`getGameIdFromName => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return getGameNameFromId(id);
} else {
warning(`getGameNameFromId => ${e.stack ?? e.message}`);
}
}
return stats.value.currentGame;
return stats.value.currentGame as string;
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/services/twitch/calls/getGameThumbnailFromName.ts
Expand Up @@ -4,6 +4,7 @@ import { getRepository } from 'typeorm';
import client from '../api/client';

import { debug, isDebugEnabled, warning } from '~/helpers/log';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

async function getGameThumbnailFromName (name: string): Promise<string | undefined> {
if (isDebugEnabled('api.calls')) {
Expand All @@ -27,7 +28,13 @@ async function getGameThumbnailFromName (name: string): Promise<string | undefin
return String(id);
} catch (e: unknown) {
if (e instanceof Error) {
warning(`getGameThumbnailFromName => ${e.stack ?? e.message}`);
if (e.message.includes('ETIMEDOUT')) {
warning(`getGameThumbnailFromName => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return getGameThumbnailFromName(name);
} else {
warning(`getGameThumbnailFromName => ${e.stack ?? e.message}`);
}
}
return undefined;
}
Expand Down
6 changes: 6 additions & 0 deletions src/services/twitch/calls/getIdFromTwitch.ts
Expand Up @@ -2,6 +2,7 @@ import client from '../api/client';
import { refresh } from '../token/refresh.js';

import { debug, error, isDebugEnabled, warning } from '~/helpers/log';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

async function getIdFromTwitch (userName: string): Promise<string> {
if (isDebugEnabled('api.calls')) {
Expand All @@ -17,6 +18,11 @@ async function getIdFromTwitch (userName: string): Promise<string> {
}
} catch (e: unknown) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`getIdFromTwitch => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return getIdFromTwitch(userName);
}
if (e.message.includes('Invalid OAuth token')) {
warning(`getIdFromTwitch => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getLatest100Followers.ts
Expand Up @@ -25,6 +25,10 @@ export async function getLatest100Followers () {
apiStats.value.currentFollowers = getFollows.total;
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
4 changes: 4 additions & 0 deletions src/services/twitch/calls/getModerators.ts
Expand Up @@ -39,6 +39,10 @@ export async function getModerators(opts: { isWarned: boolean }) {
setStatus('MOD', getModeratorsPaginated.map(o => o.userId).includes(botId));
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
return { state: false }; // ignore etimedout error
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('broadcaster');
Expand Down
8 changes: 7 additions & 1 deletion src/services/twitch/calls/getTopClips.ts
Expand Up @@ -10,8 +10,9 @@ import { streamStatusChangeSince } from '~/helpers/api';
import { getFunctionName } from '~/helpers/getFunctionName';
import { debug, error, isDebugEnabled, warning } from '~/helpers/log';
import { variables } from '~/watchers';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

export async function getTopClips (opts: any) {
export async function getTopClips (opts: any): Promise<(Partial<HelixClip> & { mp4: string; game: string | null })[]> {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand Down Expand Up @@ -39,6 +40,11 @@ export async function getTopClips (opts: any) {
return shuffle(clips).slice(0, opts.first);
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return getTopClips(opts);
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
8 changes: 7 additions & 1 deletion src/services/twitch/calls/isFollowerUpdate.ts
Expand Up @@ -4,8 +4,9 @@ import { refresh } from '../token/refresh.js';
import { getFunctionName } from '~/helpers/getFunctionName';
import client from '~/services/twitch/api/client';
import { variables } from '~/watchers';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

export async function isFollowerUpdate (id: string) {
export async function isFollowerUpdate (id: string): Promise<string | false> {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand All @@ -21,6 +22,11 @@ export async function isFollowerUpdate (id: string) {
}
} catch (e: any) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return isFollowerUpdate(id);
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
Expand Down
11 changes: 9 additions & 2 deletions src/services/twitch/calls/searchCategoriesPaginated.ts
Expand Up @@ -3,8 +3,10 @@ import { refresh } from '../token/refresh.js';

import { getFunctionName } from '~/helpers/getFunctionName';
import { debug, error, isDebugEnabled, warning } from '~/helpers/log';
import { HelixGame } from '@twurple/api/lib';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

async function searchCategoriesPaginated (game: string) {
async function searchCategoriesPaginated (game: string): Promise<HelixGame[]> {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand All @@ -13,14 +15,19 @@ async function searchCategoriesPaginated (game: string) {
return await clientBot.search.searchCategoriesPaginated(game).getAll();
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return searchCategoriesPaginated(game);
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
} else {
error(`${getFunctionName()} => ${e.stack ?? e.message}`);
}
}
return;
return [];
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/services/twitch/calls/sendGameFromTwitch.ts
Expand Up @@ -3,8 +3,9 @@ import { refresh } from '../token/refresh.js';

import { getFunctionName } from '~/helpers/getFunctionName';
import { debug, error, isDebugEnabled, warning } from '~/helpers/log';
import { setImmediateAwait } from '~/helpers/setImmediateAwait';

async function sendGameFromTwitch (game: string) {
async function sendGameFromTwitch (game: string): Promise<string[]> {
if (isDebugEnabled('api.calls')) {
debug('api.calls', new Error().stack);
}
Expand All @@ -14,14 +15,19 @@ async function sendGameFromTwitch (game: string) {
return searchCategories.map(o => o.name);
} catch (e) {
if (e instanceof Error) {
if (e.message.includes('ETIMEDOUT')) {
warning(`${getFunctionName()} => Connection to Twitch timed out. Will retry request.`);
await setImmediateAwait();
return sendGameFromTwitch(game);
}
if (e.message.includes('Invalid OAuth token')) {
warning(`${getFunctionName()} => Invalid OAuth token - attempting to refresh token`);
await refresh('bot');
} else {
error(`${getFunctionName()} => ${e.stack ?? e.message}`);
}
}
return;
return [];
}
}

Expand Down

0 comments on commit d050596

Please sign in to comment.