feat: interaction.Respond

This commit is contained in:
Yuzu 2022-07-01 09:49:04 -05:00
parent 8653e190ea
commit 60484dab40
6 changed files with 139 additions and 15 deletions

View File

@ -4,7 +4,7 @@ import type { Events } from "../handlers/Actions.ts";
import { Snowflake } from "../util/Snowflake.ts";
import { EventEmitter } from "../util/EventEmmiter.ts";
import { createGatewayManager, createRestManager } from "../vendor/external.ts";
import { createGatewayManager, createRestManager, getBotIdFromToken } from "../vendor/external.ts";
import * as Routes from "../util/Routes.ts";
import * as Actions from "../handlers/Actions.ts";
@ -39,6 +39,18 @@ export class Session extends EventEmitter {
rest: ReturnType<typeof createRestManager>;
gateway: ReturnType<typeof createGatewayManager>;
unrepliedInteractions: Set<bigint> = new Set();
#botId: Snowflake;
set botId(id: Snowflake) {
this.#botId = id;
}
get botId() {
return this.#botId;
}
constructor(options: SessionOptions) {
super();
this.options = options;
@ -71,7 +83,8 @@ export class Session extends EventEmitter {
},
handleDiscordPayload: this.options.rawHandler ?? defHandler,
});
// TODO: set botId in Session.botId or something
this.#botId = getBotIdFromToken(options.token).toString();
}
override on<K extends keyof Events>(event: K, func: Events[K]): this;

View File

@ -62,7 +62,7 @@ export class Guild extends BaseGuild implements Model {
this.vefificationLevel = data.verification_level;
this.defaultMessageNotificationLevel = data.default_message_notifications;
this.explicitContentFilterLevel = data.explicit_content_filter;
this.members = data.members?.map((member) => new Member(session, { ...member, user: member.user! })) ?? [];
this.members = data.members?.map((member) => new Member(session, { ...member, user: member.user! }, data.id)) ?? [];
this.roles = data.roles.map((role) => new Role(session, role, data.id));
this.emojis = data.emojis.map((guildEmoji) => new GuildEmoji(session, guildEmoji, data.id));
}

View File

@ -1,9 +1,42 @@
import type { Model } from "./Base.ts";
import type { Snowflake } from "../util/Snowflake.ts";
import type { Session } from "../session/Session.ts";
import type { DiscordInteraction, InteractionTypes } from "../vendor/external.ts";
import type {
DiscordMessage,
DiscordInteraction,
InteractionTypes,
InteractionResponseTypes,
FileContent,
} from "../vendor/external.ts";
import type { MessageFlags } from "../util/shared/flags.ts";
import type { AllowedMentions } from "./Message.ts";
import User from "./User.ts";
// import Member from "./Member.ts";
import Message from "./Message.ts";
import Member from "./Member.ts";
import * as Routes from "../util/Routes.ts";
export interface InteractionResponse {
type: InteractionResponseTypes;
data?: InteractionApplicationCommandCallbackData;
}
export interface InteractionApplicationCommandCallbackData {
content?: string;
tts?: boolean;
allowedMentions?: AllowedMentions;
files?: FileContent[];
customId?: string;
title?: string;
// components?: Component[];
flags?: MessageFlags;
choices?: ApplicationCommandOptionChoice[];
}
/** https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoptionchoice */
export interface ApplicationCommandOptionChoice {
name: string;
value: string | number;
}
export class Interaction implements Model {
constructor(session: Session, data: DiscordInteraction) {
@ -21,8 +54,7 @@ export class Interaction implements Model {
this.user = new User(session, data.user!);
}
else {
// TODO: member transformer
// pass
this.member = new Member(session, data.member!, data.guild_id);
}
}
@ -38,9 +70,74 @@ export class Interaction implements Model {
// deno-lint-ignore no-explicit-any
data: any;
user?: User;
member?: Member;
// TODO: do methods
async respond() {
async respond({ type, data }: InteractionResponse) {
const toSend = {
tts: data?.tts,
title: data?.title,
flags: data?.flags,
content: data?.content,
choices: data?.choices,
custom_id: data?.customId,
allowed_mentions: data?.allowedMentions
? {
users: data.allowedMentions.users,
roles: data.allowedMentions.roles,
parse: data.allowedMentions.parse,
replied_user: data.allowedMentions.repliedUser,
}
: { parse: [] },
};
if (this.session.unrepliedInteractions.delete(BigInt(this.id))) {
await this.session.rest.sendRequest<undefined>(
this.session.rest,
{
url: Routes.INTERACTION_ID_TOKEN(this.id, this.token),
method: "POST",
payload: this.session.rest.createRequestBody(this.session.rest, {
method: "POST",
body: {
type: type,
data: toSend,
file: data?.files,
},
headers: {
// remove authorization header
Authorization: "",
},
}),
}
);
return;
}
const result = await this.session.rest.sendRequest<DiscordMessage>(
this.session.rest,
{
url: Routes.WEBHOOK(this.session.botId, this.token),
method: "POST",
payload: this.session.rest.createRequestBody(this.session.rest, {
method: "POST",
body: {
...toSend,
file: data?.files
},
headers: {
// remove authorization header
Authorization: "",
},
}),
}
);
return new Message(this.session, result);
}
inGuild(): this is Interaction & { user: undefined, guildId: Snowflake, member: Member } {
return "guildId" in this;
}
}

View File

@ -63,12 +63,10 @@ export class Message implements Model {
this.attachments = data.attachments.map((attachment) => new Attachment(session, attachment));
// user is always null on MessageCreate and its replaced with author
this.member = data.member
? new Member(session, {
...data.member,
user: data.author,
})
: undefined;
if (data.guild_id && data.member) {
this.member = new Member(session, { ...data.member, user: data.author }, data.guild_id);
}
}
readonly session: Session;

View File

@ -139,3 +139,18 @@ export function INVITE(inviteCode: string, options?: GetInvite) {
export function GUILD_INVITES(guildId: Snowflake) {
return `/guilds/${guildId}/invites`;
}
export function INTERACTION_ID_TOKEN(interactionId: Snowflake, token: string) {
return `/interactions/${interactionId}/${token}/callback`;
}
export function WEBHOOK(webhookId: Snowflake, token: string, options?: { wait?: boolean; threadId?: Snowflake }) {
let url = `/webhooks/${webhookId}/${token}?`;
if (options) {
if (options.wait !== undefined) url += `wait=${options.wait}`;
if (options.threadId) url += `threadId=${options.threadId}`;
}
return url;
}

1
vendor/external.ts vendored
View File

@ -2,3 +2,4 @@ export * from "./gateway/mod.ts";
export * from "./rest/mod.ts";
export * from "./types/mod.ts";
export * from "./util/constants.ts";
export * from "./util/token.ts";