feat: better error handling

This commit is contained in:
TresAbhi committed 2023-04-26 23:42:15 +00:00
1 parent c494331470
commit 48241bd0d4
12 files changed
+347 -106

No files matched your search

-41
View File
@@ -1,41 +0,0 @@
import { Client, Routes } from 'discord.js';
import { exit } from 'process';
import discord from '../../discord.json' assert { type: 'json' };
import getClientId from '../utilities/getClientId.js';
import { rest } from './interactionCreate.js';
export const EXIT_EVENT_NAMES = [
'exit',
'SIGINT',
'SIGUSR1',
'SIGUSR2',
'uncaughtException',
];
export default function cleanup(client: Client) {
console.log('Cleaning up...');
console.log('Unregistering public commands...');
rest.put(Routes.applicationCommands(getClientId()), { body: [] });
console.log('Unregistering guild commands...');
rest.put(Routes.applicationGuildCommands(getClientId(), discord.guild_id), {
body: [],
});
console.log('Destroying client...');
try {
client.destroy();
} catch (e) {
console.error('Failed to destroy client');
console.error(e);
}
console.log('Removing all exit event listeners...');
EXIT_EVENT_NAMES.forEach((exitEventName) =>
process.off(exitEventName, () => cleanup(client)),
);
console.log('Exiting...');
exit();
}
+36
View File
@@ -0,0 +1,36 @@
import { Client, EmbedBuilder, TextChannel } from 'discord.js';
import discord from '../../discord.json' assert { type: 'json' };
import { NEGATIVE_COLOR } from '../constants/colors.js';
export const PROCESS_ERROR_EVENTS = ['uncaughtException'];
export const CLIENT_ERROR_EVENTS = ['error'];
function handleError(error: Error, client: Client) {
console.error(error);
(
client.guilds.cache
.get(discord.guild_id)
?.channels.cache.get(discord.log_channel) as TextChannel
).send({
embeds: [
new EmbedBuilder()
.setTitle('Skilled Bot ran into a catastrophic error')
.setColor(NEGATIVE_COLOR)
.setDescription(
`Total shutdown was avoided! Error:\n\n\`\`\`${error.name}\n${error.message}\n${error.stack}\n${error.cause}\`\`\``,
),
],
});
}
export function registerErrorHandlers(client: Client) {
PROCESS_ERROR_EVENTS.forEach((name) =>
process.on(name, (error) => handleError(error, client)),
);
CLIENT_ERROR_EVENTS.forEach((name) =>
client.on(name, (error) => handleError(error, client)),
);
return client;
}
+7 -11
View File
@@ -46,23 +46,19 @@ for (const file of commandFolders) {
}
try {
console.log(`Refreshing ${guildCommands.length} guild command(s).`);
const guildData = (await rest.put(
Routes.applicationGuildCommands(getClientId(), discord.guild_id),
{ body: guildCommands },
)) as RESTPostAPIChatInputApplicationCommandsJSONBody[];
console.log(`Successfully refreshed ${guildData.length} guild command(s).`);
console.log(`Refreshing ${publicCommands.length} public command(s).`);
const publicData = (await rest.put(
Routes.applicationCommands(getClientId()),
{ body: publicCommands },
)) as RESTPostAPIChatInputApplicationCommandsJSONBody[];
console.log(`Successfully refreshed ${publicData.length} public command(s).`);
console.log(`Refreshing ${guildCommands.length} guild command(s).`);
const guildData = (await rest.put(
Routes.applicationGuildCommands(getClientId(), discord.guild_id),
{ body: guildCommands },
)) as RESTPostAPIChatInputApplicationCommandsJSONBody[];
console.log(`Successfully refreshed ${guildData.length} guild command(s).`);
} catch (error) {
console.error(error);
}
+9 -4
View File
@@ -1,5 +1,10 @@
import { Client } from "discord.js";
import { Client } from 'discord.js';
import isDev from '../utilities/isDev.js';
export default function ready(client:Client<true>) {
console.log(`Logged in as ${client.user.tag}!`);
}
export default function ready(client: Client<true>) {
console.log(
`Logged in as ${client.user.tag} in ${
isDev() ? 'development' : 'production'
} mode`,
);
}
+1 -1
View File
@@ -22,7 +22,7 @@ export default {
await interaction.reply({
embeds: [
new EmbedBuilder()
.setTitle('Skilled Bot information')
.setTitle('Skilled Bot debug information')
.setColor(SKILLED_COLOR)
.setDescription(
`**Version**: ${packageJSON.version}\n**Uptime**: ${Math.floor(
+2 -2
View File
@@ -23,7 +23,7 @@ export default {
.setTitle('Skilled Bot help')
.setColor(SKILLED_COLOR)
.setDescription(
`**About**\nSkilled Bot provides many useful commands that automate many mundane tasks and provide statistics in just the right may.\Made by TresAbhi from the Skilled [SKLLD] clan.\nGitHub: https://github.com/sklld/bot\nSkilled: ADD THE LINK HERE I FORGOT\n\n**Commands**\n${(interaction.guildId ===
`**About**\nSkilled Bot automates many mundane tasks and provide statistics in many flexible ways.\n\nMade by TresAbhi from the Skilled [SKLLD] clan.\nGitHub: https://github.com/sklld/bot\nSkilled: https://discord.gg/ZPvcEG7DS8\n\n**Commands**\n${(interaction.guildId ===
discord.guild_id
? [...guildCommands, ...publicCommands]
: publicCommands
@@ -31,7 +31,7 @@ export default {
.map((command) => `**/${command.name}**: ${command.description}`)
.join(
'\n',
)})}\n\n*I am a new bot; I may make mistakes and go offline from time to time.*`,
)}\n\n*I am a new bot; I may make mistakes and go offline unexpectedly from time to time.*`,
),
],
});
+6 -10
View File
@@ -1,5 +1,5 @@
import { Client, GatewayIntentBits } from 'discord.js';
import cleanup, { EXIT_EVENT_NAMES } from './behaviors/cleanup.js';
import { registerErrorHandlers } from './behaviors/error.js';
import guildMemberAdd from './behaviors/guildMemberAdd.js';
import interactionCreate from './behaviors/interactionCreate.js';
import ready from './behaviors/ready.js';
@@ -13,12 +13,8 @@ const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
});
client.on('error', console.error);
client.on('ready', ready);
client.on('guildMemberAdd', guildMemberAdd);
client.on('interactionCreate', interactionCreate);
client.login(process.env.DISCORD_TOKEN);
EXIT_EVENT_NAMES.forEach((exitEventName) =>
process.on(exitEventName, () => cleanup(client)),
);
registerErrorHandlers(client)
.on('ready', ready)
.on('guildMemberAdd', guildMemberAdd)
.on('interactionCreate', interactionCreate)
.login(process.env.DISCORD_TOKEN);
+32 -31
View File
@@ -7,6 +7,7 @@ import fetch from 'node-fetch';
import { NEGATIVE_COLOR } from '../constants/colors.js';
import { BLITZ_SERVERS, BlitzServer } from '../constants/servers.js';
import { Player, Players } from '../types/players.js';
import wargamingError from './wargamingError.js';
export default async function getBlitzAccount(
interaction: ChatInputCommandInteraction<CacheType>,
@@ -19,37 +20,37 @@ export default async function getBlitzAccount(
`https://api.wotblitz.${server}/wotb/account/list/?application_id=${process.env.WARGAMING_APPLICATION_ID}&search=${name}`,
).then((response) => response.json())) as Players;
if (
players.status === 'ok' &&
players.data.length > 0 &&
players.data[0].nickname === name
) {
callback(players.data[0]);
} else {
// no exact match
await interaction.reply({
embeds: [
new EmbedBuilder()
.setColor(NEGATIVE_COLOR)
.setTitle(`Account not found`)
.setDescription(
`I couldn't find "${name}" in the ${serverName} server. I found ${
players?.data
? players.data.length < 100
? players.data.length
: 'over 100'
: 0
} similarly spelled account${
players?.data?.length !== 1 ? 's' : ''
}. ${
players?.data && players.data.length > 0
? `Did you mean "${players.data[0].nickname}"? `
: ''
}Re-run the command, don't make typos, and capitalize correctly.`,
),
],
});
if (players.status === 'ok') {
if (players.data.length > 0 && players.data[0].nickname === name) {
callback(players.data[0]);
} else {
// no exact match
await interaction.reply({
embeds: [
new EmbedBuilder()
.setColor(NEGATIVE_COLOR)
.setTitle(`Account not found`)
.setDescription(
`I couldn't find "${name}" in the ${serverName} server. I found ${
players?.data
? players.data.length < 100
? players.data.length
: 'over 100'
: 0
} similarly spelled account${
players?.data?.length !== 1 ? 's' : ''
}. ${
players?.data && players.data.length > 0
? `Did you mean "${players.data[0].nickname}"? `
: ''
}Re-run the command, don't make typos, and capitalize correctly.`,
),
],
});
console.log(`Account not found for ${name} in ${serverName} server.`);
console.log(`Account not found for ${name} in ${serverName} server.`);
}
} else {
wargamingError(interaction);
}
}
+1 -3
View File
@@ -1,6 +1,4 @@
import { argv } from 'process';
const isDevBoolean = argv.includes('--dev');
const isDevBoolean = process.argv.includes('--dev');
export default function isDev() {
return isDevBoolean;