From 6cafdec47a04a19fe802f418b037fa1b905526f3 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+BastiDood@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:58:36 +0800 Subject: [PATCH] fix(slash): remove deferred interaction response --- src/lib/server/api/discord.ts | 33 --------- .../webhook/discord/interaction/+server.ts | 74 +++++++++---------- .../webhook/discord/interaction/confess.ts | 12 ++- .../discord/interaction/reply-submit.ts | 14 ++-- .../webhook/discord/interaction/resend.ts | 10 +-- .../webhook/discord/interaction/util.ts | 20 +---- 6 files changed, 53 insertions(+), 110 deletions(-) diff --git a/src/lib/server/api/discord.ts b/src/lib/server/api/discord.ts index 6787db4..5ddc0e3 100644 --- a/src/lib/server/api/discord.ts +++ b/src/lib/server/api/discord.ts @@ -286,36 +286,3 @@ export async function deferResponse( botToken, ); } - -export async function createFollowupMessage( - logger: Logger, - appId: Snowflake, - token: string, - data: CreateMessage, - botToken = DISCORD_BOT_TOKEN, -) { - const body = JSON.stringify(data, (_, value) => (typeof value === 'bigint' ? value.toString() : value)); - - const start = performance.now(); - const response = await fetch(`${DISCORD_API_BASE_URL}/webhooks/${appId}/${token}`, { - body, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bot ${botToken}`, - }, - }); - const json = await response.json(); - const createFollowupMessageTimeMillis = performance.now() - start; - const child = logger.child({ createFollowupMessageTimeMillis }); - - if (response.status === 200) { - const parsed = parse(Message, json); - child.info({ createFollowupMessage: parsed }); - return parsed; - } - - const { code, message } = parse(DiscordError, json); - child.error({ statusCode: response.status }, message); - return code; -} diff --git a/src/routes/webhook/discord/interaction/+server.ts b/src/routes/webhook/discord/interaction/+server.ts index 6acfbc4..ab854b3 100644 --- a/src/routes/webhook/discord/interaction/+server.ts +++ b/src/routes/webhook/discord/interaction/+server.ts @@ -51,19 +51,19 @@ async function handleInteraction( assert(typeof interaction.member?.user !== 'undefined'); assert(typeof interaction.member.permissions !== 'undefined'); assert(hasAllPermissions(interaction.member.permissions, SEND_MESSAGES)); - await handleConfess( - db, - logger, - timestamp, - interaction.application_id, - interaction.token, - interaction.channel_id, - interaction.member.user.id, - interaction.data.options, - ); return { - type: InteractionResponseType.DeferredChannelMessageWithSource, - data: { flags: MessageFlags.Ephemeral }, + type: InteractionResponseType.ChannelMessageWithSource, + data: { + flags: MessageFlags.Ephemeral, + content: await handleConfess( + db, + logger, + timestamp, + interaction.channel_id, + interaction.member.user.id, + interaction.data.options, + ), + }, }; case 'help': return { @@ -106,19 +106,19 @@ async function handleInteraction( assert(typeof interaction.data.options !== 'undefined'); assert(typeof interaction.member?.permissions !== 'undefined'); assert(hasAllPermissions(interaction.member.permissions, MANAGE_MESSAGES)); - await handleResend( - db, - logger, - timestamp, - interaction.application_id, - interaction.token, - interaction.channel_id, - interaction.member.user.id, - interaction.data.options, - ); return { - type: InteractionResponseType.DeferredChannelMessageWithSource, - data: { flags: MessageFlags.Ephemeral }, + type: InteractionResponseType.ChannelMessageWithSource, + data: { + flags: MessageFlags.Ephemeral, + content: await handleResend( + db, + logger, + timestamp, + interaction.channel_id, + interaction.member.user.id, + interaction.data.options, + ), + }, }; case 'info': return { @@ -173,20 +173,20 @@ async function handleInteraction( assert(typeof interaction.channel_id !== 'undefined'); assert(typeof interaction.member?.user !== 'undefined'); assert(typeof interaction.member.permissions !== 'undefined'); - await handleReplySubmit( - db, - logger, - timestamp, - interaction.application_id, - interaction.token, - interaction.channel_id, - interaction.member.user.id, - interaction.member.permissions, - interaction.data.components, - ); return { - type: InteractionResponseType.DeferredChannelMessageWithSource, - data: { flags: MessageFlags.Ephemeral }, + type: InteractionResponseType.ChannelMessageWithSource, + data: { + flags: MessageFlags.Ephemeral, + content: await handleReplySubmit( + db, + logger, + timestamp, + interaction.channel_id, + interaction.member.user.id, + interaction.member.permissions, + interaction.data.components, + ), + }, }; default: fail(`unexpected modal submit ${interaction.data.custom_id}`); diff --git a/src/routes/webhook/discord/interaction/confess.ts b/src/routes/webhook/discord/interaction/confess.ts index ee12fc8..cd14178 100644 --- a/src/routes/webhook/discord/interaction/confess.ts +++ b/src/routes/webhook/discord/interaction/confess.ts @@ -55,8 +55,6 @@ async function submitConfession( db: Database, logger: Logger, timestamp: Date, - appId: Snowflake, - interactionToken: string, confessionChannelId: Snowflake, authorId: Snowflake, description: string, @@ -99,7 +97,7 @@ async function submitConfession( logger.info({ internalId, confessionId }, 'confession pending approval submitted'); // Promise is ignored so that it runs in the background - void doDeferredResponse(logger, appId, interactionToken, async () => { + void doDeferredResponse(logger, async () => { const discordErrorCode = await logPendingConfessionViaHttp( logger, timestamp, @@ -148,7 +146,7 @@ async function submitConfession( logger.info({ internalId, confessionId }, 'confession submitted'); // Promise is ignored so that it runs in the background - void doDeferredResponse(logger, appId, interactionToken, async () => { + void doDeferredResponse(logger, async () => { const message = await dispatchConfessionViaHttp( logger, timestamp, @@ -196,14 +194,14 @@ async function submitConfession( logger.info('auto-approved confession has been published'); return `${label} #${confessionId} has been published.`; }); + + return `${label} #${confessionId} has been submitted.`; } export async function handleConfess( db: Database, logger: Logger, timestamp: Date, - appId: Snowflake, - interactionToken: string, channelId: Snowflake, authorId: Snowflake, [option, ...options]: InteractionApplicationCommandChatInputOption[], @@ -212,7 +210,7 @@ export async function handleConfess( strictEqual(option?.type, InteractionApplicationCommandChatInputOptionType.String); strictEqual(option.name, 'content'); try { - await submitConfession(db, logger, timestamp, appId, interactionToken, channelId, authorId, option.value); + return await submitConfession(db, logger, timestamp, channelId, authorId, option.value); } catch (err) { if (err instanceof ConfessError) { logger.error(err, err.message); diff --git a/src/routes/webhook/discord/interaction/reply-submit.ts b/src/routes/webhook/discord/interaction/reply-submit.ts index 39462ce..83a7fec 100644 --- a/src/routes/webhook/discord/interaction/reply-submit.ts +++ b/src/routes/webhook/discord/interaction/reply-submit.ts @@ -57,8 +57,6 @@ async function submitReply( db: Database, logger: Logger, timestamp: Date, - appId: Snowflake, - interactionToken: string, permissions: bigint, confessionChannelId: Snowflake, parentMessageId: Snowflake, @@ -105,7 +103,7 @@ async function submitReply( logger.info({ internalId, confessionId }, 'reply pending approval submitted'); // Promise is ignored so that it runs in the background - void doDeferredResponse(logger, appId, interactionToken, async () => { + void doDeferredResponse(logger, async () => { const discordErrorCode = await logPendingConfessionViaHttp( logger, timestamp, @@ -154,7 +152,7 @@ async function submitReply( logger.info({ internalId, confessionId }, 'reply submitted'); // Promise is ignored so that it runs in the background - void doDeferredResponse(logger, appId, interactionToken, async () => { + void doDeferredResponse(logger, async () => { const message = await dispatchConfessionViaHttp( logger, timestamp, @@ -201,14 +199,14 @@ async function submitReply( return `${label} #${confessionId} has been published.`; }); + + return `${label} #${confessionId} has been submitted.`; } export async function handleReplySubmit( db: Database, logger: Logger, timestamp: Date, - appId: Snowflake, - interactionToken: string, channelId: Snowflake, authorId: Snowflake, permissions: bigint, @@ -226,12 +224,10 @@ export async function handleReplySubmit( const parentMessageId = BigInt(component.custom_id); try { - await submitReply( + return await submitReply( db, logger, timestamp, - appId, - interactionToken, permissions, channelId, parentMessageId, diff --git a/src/routes/webhook/discord/interaction/resend.ts b/src/routes/webhook/discord/interaction/resend.ts index 0ddaa39..514581f 100644 --- a/src/routes/webhook/discord/interaction/resend.ts +++ b/src/routes/webhook/discord/interaction/resend.ts @@ -53,8 +53,6 @@ async function resendConfession( db: Database, logger: Logger, timestamp: Date, - appId: Snowflake, - interactionToken: string, confessionChannelId: Snowflake, confessionId: bigint, moderatorId: Snowflake, @@ -88,7 +86,7 @@ async function resendConfession( logger.info('confession resend has been submitted'); // Promise is ignored so that it runs in the background - void doDeferredResponse(logger, appId, interactionToken, async () => { + void doDeferredResponse(logger, async () => { const message = await dispatchConfessionViaHttp( logger, createdAt, @@ -138,14 +136,14 @@ async function resendConfession( logger.info('confession resend has been published'); return `${label} #${confessionId} has been resent.`; }); + + return `${label} #${confessionId} has been submitted as a resent confession.`; } export async function handleResend( db: Database, logger: Logger, timestamp: Date, - appId: Snowflake, - interactionToken: string, channelId: Snowflake, moderatorId: Snowflake, [option, ...options]: InteractionApplicationCommandChatInputOption[], @@ -156,7 +154,7 @@ export async function handleResend( const confessionId = BigInt(option.value); try { - await resendConfession(db, logger, timestamp, appId, interactionToken, channelId, confessionId, moderatorId); + return await resendConfession(db, logger, timestamp, channelId, confessionId, moderatorId); } catch (err) { if (err instanceof ResendError) { logger.error(err, err.message); diff --git a/src/routes/webhook/discord/interaction/util.ts b/src/routes/webhook/discord/interaction/util.ts index 38ed051..f24d9c9 100644 --- a/src/routes/webhook/discord/interaction/util.ts +++ b/src/routes/webhook/discord/interaction/util.ts @@ -4,28 +4,12 @@ import type { Logger } from 'pino'; import type { InteractionApplicationCommandChatInputOption } from '$lib/server/models/discord/interaction/application-command/chat-input/option'; import { InteractionApplicationCommandChatInputOptionType } from '$lib/server/models/discord/interaction/application-command/chat-input/option/base'; -import { MessageFlags } from '$lib/server/models/discord/message/base'; -import type { Snowflake } from '$lib/server/models/discord/snowflake'; -import { UnexpectedDiscordErrorCode } from './errors'; -import { createFollowupMessage } from '$lib/server/api/discord'; - -export async function doDeferredResponse( - logger: Logger, - appId: Snowflake, - interactionToken: string, - callback: () => Promise, -) { +export async function doDeferredResponse(logger: Logger, callback: () => Promise) { const start = performance.now(); const content = await callback(); const deferredResponseTimeMillis = performance.now() - start; - logger.info({ deferredResponseTimeMillis }, 'deferred response complete'); - - const result = await createFollowupMessage(logger, appId, interactionToken, { - flags: MessageFlags.Ephemeral, - content, - }); - if (typeof result === 'number') throw new UnexpectedDiscordErrorCode(result); + logger.info({ deferredResponseTimeMillis, content }, 'deferred response complete'); } export function parsePublic(arg?: InteractionApplicationCommandChatInputOption) {