mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: mature error handling system
This commit is contained in:
1 parent
1875f30cf5
commit
524edac615
23 files changed
+87
-87
No files matched your search
@@ -13,7 +13,7 @@ const executionStart = new Date().getTime();
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -26,7 +26,7 @@ export const SKILLED_CLANS: Record<SkilledClan, string> = {
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: false,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -11,7 +11,7 @@ import { client } from '../index.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -40,7 +40,7 @@ const COMP_TANKS = [
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -17,7 +17,7 @@ type SortBy = 'name' | 'count';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AccountInfo } from '../types/accountInfo.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ClanList } from '../types/clanList.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AccountList } from '../types/accountList.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -9,7 +9,7 @@ import { CommandRegistry } from '../events/interactionCreate.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -40,7 +40,7 @@ import { PlayerClanData } from '../types/playerClanData.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -40,7 +40,7 @@ import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -14,7 +14,7 @@ import { PlayerClanData } from '../types/playerClanData.js';
|
||||
|
||||
export default {
|
||||
inProduction: true,
|
||||
inDevelopment: false,
|
||||
inDevelopment: true,
|
||||
inPublic: true,
|
||||
|
||||
command: new SlashCommandBuilder()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { BlitzServer } from '../../constants/servers.js';
|
||||
import negativeEmbed from '../interaction/negativeEmbed.js';
|
||||
import errorWithCause from '../process/errorWithCause.js';
|
||||
import listAccountsPanServer, {
|
||||
usernamePatternWithoutPosition,
|
||||
} from './listAccountsPanServer.js';
|
||||
@@ -17,17 +17,9 @@ export default async function getBlitzAccount(
|
||||
const username = commandUsername ?? displayName;
|
||||
|
||||
if (username === undefined) {
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
'Username could not be inferred',
|
||||
"You didn't provide me a username in the command nor was I able to infer your Blitz username from your Discord nickname. Try providing a username manually in the command or using the `/verify` command to set your Discord nickname to your Blitz username.",
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
throw new Error(
|
||||
`No username provided commandUsername: ${commandUsername} displayName: ${displayName} username: ${username}`,
|
||||
throw errorWithCause(
|
||||
'Username could not be inferred',
|
||||
"You didn't provide me a username in the command nor was I able to infer your Blitz username from your Discord nickname. Try providing a username manually in the command or using the `/verify` command to set your Discord nickname to your Blitz username.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,16 +32,10 @@ export default async function getBlitzAccount(
|
||||
if (accounts[0]) {
|
||||
return { server: accounts[0].server, id: accounts[0].account_id };
|
||||
} else {
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
'Could not find user',
|
||||
`I couldn't find user \`${username}\`. Try providing a username manually or using the \`/verify\` command to set your Discord nickname to your Blitz username.`,
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
throw new Error(`Could not find user "${username}"`);
|
||||
throw errorWithCause(
|
||||
'Could not find user',
|
||||
`I couldn't find user \`${username}\`. Try providing a valid username manually or using the \`/verify\` command to set your Discord nickname to your Blitz username.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { BlitzServer } from '../../constants/servers.js';
|
||||
import negativeEmbed from '../interaction/negativeEmbed.js';
|
||||
import errorWithCause from '../process/errorWithCause.js';
|
||||
import { serverAndIdPattern } from './getBlitzAccount.js';
|
||||
import listClansPanServer from './listClansPanServer.js';
|
||||
|
||||
@@ -17,16 +17,10 @@ export default async function getBlitzClan(
|
||||
if (accounts[0]) {
|
||||
return { server: accounts[0].server, id: accounts[0].clan_id };
|
||||
} else {
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
'Could not find clan',
|
||||
`I couldn't find clan \`${clan}\`. Try selecting a username from the search result.`,
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
throw new Error(`Could not find clan "${clan}"`);
|
||||
throw errorWithCause(
|
||||
'Could not find clan',
|
||||
`I couldn't find clan \`${clan}\`. Try selecting a username from the search result.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { BLITZ_SERVERS, BlitzServer } from '../../constants/servers.js';
|
||||
import { TanksStats } from '../../types/tanksStats.js';
|
||||
import negativeEmbed from '../interaction/negativeEmbed.js';
|
||||
import { args } from '../process/args.js';
|
||||
import errorWithCause from '../process/errorWithCause.js';
|
||||
import getWargamingResponse from './getWargamingResponse.js';
|
||||
|
||||
export default async function getTankStats(
|
||||
@@ -15,16 +15,10 @@ export default async function getTankStats(
|
||||
);
|
||||
|
||||
if (tankStats[id] === null) {
|
||||
interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
'No tank stats available',
|
||||
`Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${BLITZ_SERVERS[server]} server.`,
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
throw new Error(`No tank stats available for ${server}/${id}`);
|
||||
throw errorWithCause(
|
||||
'No tank stats available',
|
||||
`Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${BLITZ_SERVERS[server]} server.`,
|
||||
);
|
||||
}
|
||||
|
||||
return tankStats[id];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { WargamingResponse } from '../../types/wargamingResponse.js';
|
||||
import errorWithCause from '../process/errorWithCause.js';
|
||||
|
||||
export default async function getWargamingResponse<Data extends object>(
|
||||
url: string,
|
||||
@@ -11,8 +12,9 @@ export default async function getWargamingResponse<Data extends object>(
|
||||
if (parsed.status === 'ok') {
|
||||
return parsed.data;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Wargaming response error status:"${parsed.status}" message: "${parsed.error.message}" url: "${url}"`,
|
||||
throw errorWithCause(
|
||||
`Wargaming response error status:"${parsed.status}"`,
|
||||
`Message: "${parsed.error.message}"\nURL: "${url}"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
import negativeEmbed from '../interaction/negativeEmbed.js';
|
||||
import errorWithCause from '../process/errorWithCause.js';
|
||||
import { TANKS, tankopedia } from './tankopedia.js';
|
||||
|
||||
export default async function resolveTankId(
|
||||
@@ -13,16 +13,10 @@ export default async function resolveTankId(
|
||||
const searchResult = go(tank, TANKS, { keys: ['name'], limit: 1 });
|
||||
|
||||
if (searchResult.length === 0) {
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
'Tank not found',
|
||||
`Could not find tank by the name "${tank}".`,
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
throw new Error(`Tank not found by name "${tank}"`);
|
||||
throw errorWithCause(
|
||||
'Tank not found',
|
||||
`Could not find tank by the name "${tank}".`,
|
||||
);
|
||||
} else {
|
||||
return searchResult[0].obj.tank_id;
|
||||
}
|
||||
@@ -30,16 +24,10 @@ export default async function resolveTankId(
|
||||
if (tankopedia[number]) {
|
||||
return number;
|
||||
} else {
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
'Tank not found',
|
||||
`Could not find tank by the ID "${number}".`,
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
throw new Error(`Tank not found by ID "${number}"`);
|
||||
throw errorWithCause(
|
||||
'Tank not found',
|
||||
`Could not find tank by the ID "${number}".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,5 +22,5 @@ export default async function wargamingError(
|
||||
});
|
||||
|
||||
console.log(`Wargaming returned an error`);
|
||||
handleError(error, client, command);
|
||||
handleError(error, command);
|
||||
}
|
||||
@@ -24,5 +24,5 @@ export default async function blitzStarsError(
|
||||
});
|
||||
|
||||
console.log(`BlitzStars returned an error`);
|
||||
handleError(error, client, command);
|
||||
handleError(error, command);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { argv } from 'process';
|
||||
import errorWithCause from './errorWithCause.js';
|
||||
|
||||
type ArgumentName = 'discord-token' | 'wargaming-application-id';
|
||||
|
||||
@@ -16,6 +17,9 @@ argv.forEach((arg) => {
|
||||
|
||||
Object.keys(args).forEach((arg) => {
|
||||
if (args[arg as ArgumentName] === '') {
|
||||
throw new Error(`Missing argument: ${arg}`);
|
||||
throw errorWithCause(
|
||||
`Missing argument: ${arg}`,
|
||||
'Missing required auth key.',
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function errorWithCause(message: string, cause: string) {
|
||||
return new Error(message, { cause });
|
||||
}
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
import { Client, EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import { EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import discord from '../../discord.json' assert { type: 'json' };
|
||||
import { NEGATIVE_COLOR } from '../constants/colors.js';
|
||||
import isDev from '../core/process/isDev.js';
|
||||
@@ -7,7 +7,7 @@ import { client } from '../index.js';
|
||||
const PROCESS_ERROR_EVENTS = ['uncaughtException'];
|
||||
const CLIENT_ERROR_EVENTS = ['error'];
|
||||
|
||||
export function handleError(error: Error, client: Client, command: string) {
|
||||
export function handleError(error: Error, command: string) {
|
||||
console.error(error);
|
||||
|
||||
(
|
||||
@@ -31,10 +31,10 @@ export function handleError(error: Error, client: Client, command: string) {
|
||||
export function registerErrorHandlers() {
|
||||
if (!isDev()) {
|
||||
PROCESS_ERROR_EVENTS.forEach((name) =>
|
||||
process.on(name, (error) => handleError(error, client, 'process error')),
|
||||
process.on(name, (error) => handleError(error, 'process error')),
|
||||
);
|
||||
CLIENT_ERROR_EVENTS.forEach((name) =>
|
||||
client.on(name, (error) => handleError(error, client, 'client error')),
|
||||
client.on(name, (error) => handleError(error, 'client error')),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
AutocompleteInteraction,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
CacheType,
|
||||
ChatInputCommandInteraction,
|
||||
Collection,
|
||||
@@ -11,9 +14,11 @@ import {
|
||||
} from 'discord.js';
|
||||
import { readdirSync } from 'fs';
|
||||
import discord from '../../discord.json' assert { type: 'json' };
|
||||
import negativeEmbed from '../core/interaction/negativeEmbed.js';
|
||||
import { args } from '../core/process/args.js';
|
||||
import getClientId from '../core/process/getClientId.js';
|
||||
import isDev from '../core/process/isDev.js';
|
||||
import { handleError } from './error.js';
|
||||
|
||||
export interface CommandRegistry {
|
||||
inDevelopment: boolean;
|
||||
@@ -101,6 +106,30 @@ export default async function interactionCreate(
|
||||
|
||||
console.log(interaction.toString());
|
||||
await interaction.deferReply();
|
||||
command.execute(interaction);
|
||||
|
||||
try {
|
||||
await command.execute(interaction);
|
||||
} catch (error) {
|
||||
const actionRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('Get Help on Discord Server')
|
||||
.setURL('https://discord.gg/nDt7AjGJQH')
|
||||
.setStyle(ButtonStyle.Link),
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [
|
||||
negativeEmbed(
|
||||
(error as Error).message,
|
||||
`${
|
||||
(error as Error).cause ?? 'No further information is available.'
|
||||
}`,
|
||||
),
|
||||
],
|
||||
components: [actionRow],
|
||||
});
|
||||
|
||||
handleError(error as Error, interaction.commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user