From c1a14fdac1e0eb3079e26861fcd822665df9559d Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Sun, 14 Mar 2021 15:46:44 +0530 Subject: [PATCH] http slash commands --- src/models/slashClient.ts | 41 +++++++++++++++++++++++++++++++++++---- src/structures/slash.ts | 14 +++++++++---- src/test/slash-http.ts | 27 +++++--------------------- 3 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/models/slashClient.ts b/src/models/slashClient.ts index 5f8955d..33b3aca 100644 --- a/src/models/slashClient.ts +++ b/src/models/slashClient.ts @@ -1,7 +1,11 @@ import { Guild } from '../structures/guild.ts' -import { Interaction } from '../structures/slash.ts' +import { + Interaction, + InteractionApplicationCommandResolved +} from '../structures/slash.ts' import { InteractionPayload, + InteractionResponsePayload, InteractionType, SlashCommandChoice, SlashCommandOption, @@ -14,6 +18,7 @@ import { Client } from './client.ts' import { RESTManager } from './rest.ts' import { SlashModule } from './slashModule.ts' import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts' +import { User } from '../structures/user.ts' export class SlashCommand { slash: SlashCommandsManager @@ -372,6 +377,9 @@ export interface SlashOptions { publicKey?: string } +const encoder = new TextEncoder() +const decoder = new TextDecoder('utf-8') + /** Slash Client represents an Interactions Client which can be used without Harmony Client. */ export class SlashClient { id: string | (() => string) @@ -537,16 +545,17 @@ export class SlashClient { return edverify(signature, fullBody, this.publicKey).catch(() => false) } - /** Verify [Deno Std HTTP Server Request](https://deno.land/std/http/server.ts) and return Interaction */ + /** Verify [Deno Std HTTP Server Request](https://deno.land/std/http/server.ts) and return Interaction. **Data present in Interaction returned by this method is very different from actual typings as there is no real `Client` behind the scenes to cache things.** */ async verifyServerRequest(req: { headers: Headers method: string body: Deno.Reader respond: (options: { status?: number + headers?: Headers body?: string | Uint8Array }) => Promise - }): Promise { + }): Promise { if (req.method.toLowerCase() !== 'post') return false const signature = req.headers.get('x-signature-ed25519') @@ -559,7 +568,31 @@ export class SlashClient { try { const payload: InteractionPayload = JSON.parse(decoder.decode(rawbody)) - const res = new Interaction(this as any, payload, {}) + + // TODO: Maybe fix all this hackery going on here? + const res = new Interaction(this as any, payload, { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + user: new User(this as any, (payload.member?.user ?? payload.user)!), + member: payload.member as any, + guild: payload.guild_id as any, + channel: payload.channel_id as any, + resolved: ((payload.data + ?.resolved as unknown) as InteractionApplicationCommandResolved) ?? { + users: {}, + members: {}, + roles: {}, + channels: {} + } + }) + res._httpRespond = async (d: InteractionResponsePayload) => + await req.respond({ + status: 200, + headers: new Headers({ + 'content-type': 'application/json' + }), + body: JSON.stringify(d) + }) + return res } catch (e) { return false diff --git a/src/structures/slash.ts b/src/structures/slash.ts index 9b8cc10..259151b 100644 --- a/src/structures/slash.ts +++ b/src/structures/slash.ts @@ -108,6 +108,8 @@ export class Interaction extends SnowflakeBase { resolved: InteractionApplicationCommandResolved /** Whether response was deferred or not */ deferred: boolean = false + _httpRespond?: (d: InteractionResponsePayload) => unknown + _httpResponded?: boolean constructor( client: Client, @@ -180,10 +182,14 @@ export class Interaction extends SnowflakeBase { : undefined } - await this.client.rest.post( - INTERACTION_CALLBACK(this.id, this.token), - payload - ) + if (this._httpRespond !== undefined && this._httpResponded !== true) { + this._httpResponded = true + await this._httpRespond(payload) + } else + await this.client.rest.post( + INTERACTION_CALLBACK(this.id, this.token), + payload + ) this.responded = true return this diff --git a/src/test/slash-http.ts b/src/test/slash-http.ts index 02f9836..893feaf 100644 --- a/src/test/slash-http.ts +++ b/src/test/slash-http.ts @@ -18,27 +18,10 @@ await slash.commands.bulkEdit([ const options = { port: 8000 } console.log('Listen on port: ' + options.port.toString()) listenAndServe(options, async (req) => { - const verify = await slash.verifyServerRequest(req) - if (verify === false) - return req.respond({ status: 401, body: 'not authorized' }) + const d = await slash.verifyServerRequest(req) + if (d === false) return req.respond({ status: 401, body: 'not authorized' }) - const respond = async (d: any): Promise => - req.respond({ - status: 200, - body: JSON.stringify(d), - headers: new Headers({ - 'content-type': 'application/json' - }) - }) - - const body = JSON.parse( - new TextDecoder('utf-8').decode(await Deno.readAll(req.body)) - ) - if (body.type === 1) return await respond({ type: 1 }) - await respond({ - type: 4, - data: { - content: 'Pong!' - } - }) + console.log(d) + if (d.type === 1) return d.respond({ type: 1 }) + d.reply('Pong!') })