From f05eede3aa831a74ea962f2fd5e2284ea2ea001e Mon Sep 17 00:00:00 2001 From: WhatCats Date: Mon, 29 Jul 2024 04:37:01 +0200 Subject: [PATCH] fix request failure handling --- src/lib/apis/request.ts | 11 +++++++++-- src/lib/discord/CommandHandler.ts | 12 +++++++++++- src/modules/council/list-members.ts | 3 ++- src/modules/rank-apps/CouncilVoteManager.ts | 8 +++++--- src/modules/vouch-system/public-commands.ts | 5 +++-- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/lib/apis/request.ts b/src/lib/apis/request.ts index 6cfb9cf..a2ffd68 100644 --- a/src/lib/apis/request.ts +++ b/src/lib/apis/request.ts @@ -8,6 +8,10 @@ export interface RequestOptions extends RequestInit { export class RequestError extends Error { name = "RequestError" + + constructor(msg: string, cause?: Error) { + super(msg, { cause }) + } } export class TimeoutError extends RequestError { @@ -29,9 +33,12 @@ export async function request(url: string, options: RequestOptions = {}): Promis const timeoutId = setTimeout(() => controller.abort(), (options.timeout || 10) * 1000) if (options.urlParams) url += `?${new URLSearchParams(options.urlParams)}` - function requestError(): Response { + function requestError(error: Error): Response { if (controller.signal.aborted) throw new TimeoutError("Server took too long to respond") - throw new RequestError("Network unavailable") + if (error instanceof TypeError) { + error = error.cause as Error + } + throw new RequestError("Request Failed", error) } return fetch(url, { ...options, signal: controller.signal, cache: "no-cache" }) diff --git a/src/lib/discord/CommandHandler.ts b/src/lib/discord/CommandHandler.ts index b967a1c..e8f2ba9 100644 --- a/src/lib/discord/CommandHandler.ts +++ b/src/lib/discord/CommandHandler.ts @@ -114,7 +114,17 @@ export class CommandHandler { if (error instanceof DiscordAPIError && [10062].includes(error.code as number)) return if (!(error instanceof UserError) && !(error instanceof LocalizedError)) - console.error("Unexpected error while handling a command!", error) + console.error( + "Unexpected error while handling a command!", + { + command: interaction.path, + type: interaction.type, + user: interaction.user.id, + channel: interaction.channelId, + guild: interaction.guildId, + }, + error, + ) // Give the user that error message they were missing in their life if ( diff --git a/src/modules/council/list-members.ts b/src/modules/council/list-members.ts index e6d2dfc..e0ffc74 100644 --- a/src/modules/council/list-members.ts +++ b/src/modules/council/list-members.ts @@ -17,7 +17,8 @@ SlashCommand({ option .setName(Options.Rank) .setDescription("The rank to list the members of.") - .setChoices(Object.values(RANKS).map((v) => ({ name: v, value: v }))), + .setChoices(Object.values(RANKS).map((v) => ({ name: v, value: v }))) + .setRequired(true), ), config: { permissions: COUNCIL_PERMISSIONS }, diff --git a/src/modules/rank-apps/CouncilVoteManager.ts b/src/modules/rank-apps/CouncilVoteManager.ts index d0648bd..60270fb 100644 --- a/src/modules/rank-apps/CouncilVoteManager.ts +++ b/src/modules/rank-apps/CouncilVoteManager.ts @@ -135,7 +135,7 @@ Component({ async handler(interaction) { const { ticketManager, ticket } = await RankAppTicketManager.findTicket(interaction) if (!(ticketManager instanceof RankAppTicketManager)) - throw new Error(`${interaction.customId} in non RankAppTicketManager channel!`) + throw new UserError(`This interaction is not available in this channel.`) if (!interaction.userHasPosition(`${ticketManager.rank} Council`)) throw new LocalizedError("command_handler.missing_permissions") @@ -144,10 +144,12 @@ Component({ if (isNaN(vote)) throw new Error(`Got invalid vote value of ${vote} from ${interaction.customId}!`) await ticket.updateOne({ $set: { [`extras.votes.${interaction.user.id}`]: vote } }) - ticket.extras!.votes[interaction.user.id] = vote + + if (!ticket.extras) ticket.extras = { votes: {} } + ticket.extras.votes[interaction.user.id] = vote await interaction.update( - ticketManager.vote.buildVoteMessage(ticket.user(), interaction.guild!, ticket.extras!.votes), + ticketManager.vote.buildVoteMessage(ticket.user(), interaction.guild!, ticket.extras.votes), ) }, }) diff --git a/src/modules/vouch-system/public-commands.ts b/src/modules/vouch-system/public-commands.ts index 62d58e9..da31435 100644 --- a/src/modules/vouch-system/public-commands.ts +++ b/src/modules/vouch-system/public-commands.ts @@ -3,10 +3,10 @@ import { ApplicationCommandOptionChoiceData, SlashCommandStringOption, User } fr import { ContextMenu, ContextMenuInteraction, - HTTPError, LocalizedContextMenuCommandBuilder, LocalizedError, LocalizedSlashCommandBuilder, + RequestError, SlashCommand, SlashCommandInteraction, TimeoutError, @@ -156,8 +156,9 @@ async function finishVouchesInteraction( async function fetchUserId(ign: string) { const url = `https://api.scrims.network/v1/user?${new URLSearchParams({ username: ign })}` const resp = await request(url).catch((error) => { - if (error instanceof HTTPError) throw new LocalizedError(`api.request_failed`, "Scrims Network API") if (error instanceof TimeoutError) throw new LocalizedError("api.timeout", "Scrims Network API") + if (error instanceof RequestError) + throw new LocalizedError(`api.request_failed`, "Scrims Network API") throw error })