Skip to content

Commit

Permalink
fix(slash): remove deferred interaction response
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiDood committed Dec 15, 2024
1 parent 5431bf5 commit 6cafdec
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 110 deletions.
33 changes: 0 additions & 33 deletions src/lib/server/api/discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
74 changes: 37 additions & 37 deletions src/routes/webhook/discord/interaction/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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}`);
Expand Down
12 changes: 5 additions & 7 deletions src/routes/webhook/discord/interaction/confess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ async function submitConfession(
db: Database,
logger: Logger,
timestamp: Date,
appId: Snowflake,
interactionToken: string,
confessionChannelId: Snowflake,
authorId: Snowflake,
description: string,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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[],
Expand All @@ -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);
Expand Down
14 changes: 5 additions & 9 deletions src/routes/webhook/discord/interaction/reply-submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ async function submitReply(
db: Database,
logger: Logger,
timestamp: Date,
appId: Snowflake,
interactionToken: string,
permissions: bigint,
confessionChannelId: Snowflake,
parentMessageId: Snowflake,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
10 changes: 4 additions & 6 deletions src/routes/webhook/discord/interaction/resend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ async function resendConfession(
db: Database,
logger: Logger,
timestamp: Date,
appId: Snowflake,
interactionToken: string,
confessionChannelId: Snowflake,
confessionId: bigint,
moderatorId: Snowflake,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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[],
Expand All @@ -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);
Expand Down
20 changes: 2 additions & 18 deletions src/routes/webhook/discord/interaction/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>,
) {
export async function doDeferredResponse(logger: Logger, callback: () => Promise<string>) {
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) {
Expand Down

0 comments on commit 6cafdec

Please sign in to comment.