From 0e33185f163dabcf0293d2947eb9cbd867494b0b Mon Sep 17 00:00:00 2001 From: ION606 Date: Mon, 20 Mar 2023 12:45:20 -0400 Subject: [PATCH] Added Interaction integration --- .gitignore | 1 - package.json | 2 +- structures/client/client.js | 22 ++- structures/client/handleEvents.js | 9 +- structures/interactions/interaction.js | 183 +++++++++++++++++++++++++ structures/messages/message.js | 4 +- structures/types.js | 3 +- tests/interactionTests.js | 12 ++ tests/messageTests.js | 21 +++ tests/test.js | 37 +++++ 10 files changed, 286 insertions(+), 8 deletions(-) create mode 100644 structures/interactions/interaction.js create mode 100644 tests/interactionTests.js create mode 100644 tests/messageTests.js create mode 100644 tests/test.js diff --git a/.gitignore b/.gitignore index cddcf75..95b863a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ config.json node_modules -test.js diff --git a/package.json b/package.json index fa7291a..7803794 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "custom_discordjs", "version": "1.0.0", "description": "because discord.js is annoying", - "main": "test.js", + "main": "tests\\test.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/structures/client/client.js b/structures/client/client.js index a4944d8..4e1a6b0 100644 --- a/structures/client/client.js +++ b/structures/client/client.js @@ -6,6 +6,7 @@ const WebSocketConnection = require('websocket').connection; const handleResponses = require('./handleEvents.js'); const { EventEmitter } = require('events'); const axios = require('axios'); +const { exit } = require('process'); @@ -43,6 +44,15 @@ class Client extends EventEmitter { this.gwintents = input.intents; } + async #heartbeat(hbInt, hbSequence) { + const toSend = JSON.stringify({ op: 1, d: 0 }); + this.connection.send((toSend)); + + setInterval(() => { + this.connection.send(toSend); + }, hbInt); + } + /** * @param {Number} hbint */ @@ -71,6 +81,7 @@ class Client extends EventEmitter { }; this.connection.send(JSON.stringify(idObj)); + this.#heartbeat(hbint); } @@ -86,6 +97,9 @@ class Client extends EventEmitter { this.emit('error', err); } + interactionRecieved(interaction) { + this.emit('interactionRecieved', interaction); + } /** * @param {String} token @@ -101,7 +115,7 @@ class Client extends EventEmitter { connection.on('message', async (msg) => { const data = JSON.parse(msg.utf8Data); - const response = await handleResponses(data, token); + const response = await handleResponses(data, token, this.id); if (response.op == 10) { this.#startHeartBeat(response.heartBeat, token); } else if (response.op == 0) { @@ -116,6 +130,11 @@ class Client extends EventEmitter { this.messageRecieved(response.message); } } + else if (response.t == gateWayEvents.InteractionCreate) { + if (data["d"]["user"]["id"] != this.user_profile.id) { + this.interactionRecieved(response.interaction); + } + } else console.log(response.t); } else { console.log(response.t); @@ -124,6 +143,7 @@ class Client extends EventEmitter { connection.on('close', (code, desc) => { console.log(`CONNECTION CLOSED WITH CODE ${code}\nREASON:\n ${desc}`); + exit(1); }); connection.on('error', (err) => { diff --git a/structures/client/handleEvents.js b/structures/client/handleEvents.js index 4fda25d..bf3bc60 100644 --- a/structures/client/handleEvents.js +++ b/structures/client/handleEvents.js @@ -1,6 +1,7 @@ const { exit } = require('process'); const gateWayEvents = require('../gateway/dispatch.js'); const { message } = require('../messages/message.js'); +const Interaction = require('../interactions/interaction.js'); /** @@ -8,7 +9,7 @@ const { message } = require('../messages/message.js'); * @param {Object} msg * @returns {Promise} */ -module.exports = async function handleEvents(msgObj, token) { +module.exports = async function handleEvents(msgObj, token, id) { return new Promise((resolve, reject) => { const op = msgObj["op"]; const t = msgObj["t"]; @@ -17,10 +18,14 @@ module.exports = async function handleEvents(msgObj, token) { if (op == 0 && t == gateWayEvents.Ready) { resolve({op: op, t: t, config: msgObj["d"]["user_settings"], profile: msgObj["d"]["user"] }); - } else if (t == gateWayEvents.MessageCreate) { + } + else if (t == gateWayEvents.MessageCreate) { const msg = new message(msgObj["d"], token); resolve({op: op, t: t, message: msg}); } + else if (t == gateWayEvents.InteractionCreate) { + resolve({op: op, t: t, interaction: new Interaction(msgObj["d"], token, id)}); + } else { // console.log(t); diff --git a/structures/interactions/interaction.js b/structures/interactions/interaction.js new file mode 100644 index 0000000..3697469 --- /dev/null +++ b/structures/interactions/interaction.js @@ -0,0 +1,183 @@ +const axios = require('axios'); +const author = require('../messages/author.js'); +const { Channel, message } = require('../messages/message.js'); +const Embed = require('../messages/embed.js'); + + +class Interaction { + /** @type {author} */ + user; + + /** @type {Number} */ + type; + + /** @type {String} */ + #token; + + /** @type {{token: String, id: String}} */ + #application; + + /** @type {String} */ + id; + + /** @type {String} */ + channel_id; + + /** @type {Channel} */ + channel; + + /** @type {String} */ + application_id; + + + /** + * @param {{content: String, ephemeral?: Boolean, embeds: [Embed]} | String} inp + * @returns {Promise} + */ + async reply(inp) { + return new Promise(async (resolve, reject) => { + const toSend = (typeof inp == 'string') ? inp : inp.content; + + const config = { + headers: { + Authorization: this.#application.token + } + } + + var embds = undefined; + if (inp.embeds) { + embds = []; + for (const i of inp.embeds) { + embds.push(i.toJSON()); + } + } + + const response = await axios.post(`https://discord.com/api/interactions/${this.id}/${this.#token}/callback`, { + type: 4, + data: { + content: toSend, + embeds: embds, + flags: (inp.ephemeral) ? (1 << 6) : undefined + } + }, config); + + resolve(new message(response.data, this.#application.token)); + }); + } + + + async update(inp) { + return new Promise(async (resolve, reject) => { + try { + const toSend = (typeof inp == 'string') ? inp : inp.content; + + const config = { + headers: { + Authorization: this.#application.token + } + } + + var embds = undefined; + if (inp.embeds) { + embds = []; + for (const i of inp.embeds) { + embds.push(i.toJSON()); + } + } + + const response = await axios.patch(`https://discord.com/api/webhooks/${this.#application.id}/${this.#token}/messages/@original`, { + content: toSend, + embeds: embds, + flags: (inp.ephemeral) ? (1 << 6) : undefined + }, config); + + // const response = await axios.get(`https://discord.com/api/webhooks/${this.#application.id}/${this.#token}/messages/@original`, config); + + resolve(new message(response.data, this.#application.token)); + } catch(err) { + reject(err); + } + }); + } + + + /** + * @param {*} inp + * @returns {Promise} + */ + async followUp(inp) { + return new Promise(async (resolve, reject) => { + try { + const toSend = (typeof inp == 'string') ? inp : inp.content; + + const config = { + headers: { + Authorization: this.#application.token + } + } + + var embds = undefined; + if (inp.embeds) { + embds = []; + for (const i of inp.embeds) { + embds.push(i.toJSON()); + } + } + + const response = await axios.post(`https://discord.com/api/webhooks/${this.#application.id}/${this.#token}`, { + content: toSend, + embeds: embds, + flags: (inp.ephemeral) ? (1 << 6) : undefined + }, config); + + // const response = await axios.get(`https://discord.com/api/webhooks/${this.#application.id}/${this.#token}/messages/@original`, config); + + resolve(new message(response.data, this.#application.token)); + } catch(err) { + reject(err); + } + }); + } + + + /** + * @returns {Promise} Returns true if successful + */ + async delete() { + return new Promise(async (resolve, reject) => { + try { + const response = await axios.delete(`https://discord.com/api/webhooks/${this.#application.id}/${this.#token}/messages/@original`); + + resolve(response.status == 204); + } catch (err) { + reject(err); + } + }); + } + + + /** + * @param {Object} intRaw + */ + constructor(intRaw, token, apid) { + this.#application = {token: token, id: apid}; + this.#token = intRaw["token"]; + + for (const k in this) { + if (intRaw[k] != undefined) { + if (k == "user") this[k] = new author(intRaw[k]); + + else { + if (k == 'channel_id') { + this.channel = new Channel(this.#application.token, intRaw[k]); + } + + this[k] = intRaw[k]; + } + } + } + } +} + + +module.exports = Interaction; \ No newline at end of file diff --git a/structures/messages/message.js b/structures/messages/message.js index f5737b3..e230153 100644 --- a/structures/messages/message.js +++ b/structures/messages/message.js @@ -18,7 +18,7 @@ class Channel { /** * @param {Object} inp - * @returns {message} + * @returns {Promise} */ async send(inp) { return new Promise(async (resolve) => { @@ -191,4 +191,4 @@ class message { } -module.exports = { message, messageChannelTypes }; \ No newline at end of file +module.exports = { message, messageChannelTypes, Channel }; \ No newline at end of file diff --git a/structures/types.js b/structures/types.js index bf2fc7a..32d037c 100644 --- a/structures/types.js +++ b/structures/types.js @@ -2,6 +2,7 @@ const {message} = require('./messages/message'); const {Client, gateWayIntents} = require('./client/client.js'); const Embed = require('./messages/embed'); const messageChannelTypes = require('./messages/messageChannelTypes'); +const Interaction = require('./interactions/interaction.js'); -module.exports = { message, Client, gateWayIntents, Embed, messageChannelTypes } \ No newline at end of file +module.exports = { message, Client, gateWayIntents, Embed, messageChannelTypes, Interaction } \ No newline at end of file diff --git a/tests/interactionTests.js b/tests/interactionTests.js new file mode 100644 index 0000000..bf7e9fb --- /dev/null +++ b/tests/interactionTests.js @@ -0,0 +1,12 @@ +const { Interaction } = require('../structures/types'); +const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); + +module.exports = /** @param {Interaction} interaction */ async (interaction) => { + interaction.reply({content: "HELLO WORLD", ephemeral: true}); + await delay(3000); + interaction.update({content: "NOOOOOOOOOOOOOOOOOO"}); + await delay(2000); + const response = await interaction.followUp("followup!"); + await delay(2000); + response.delete(); +} \ No newline at end of file diff --git a/tests/messageTests.js b/tests/messageTests.js new file mode 100644 index 0000000..acb65b8 --- /dev/null +++ b/tests/messageTests.js @@ -0,0 +1,21 @@ +const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); +const {message, Embed, messageChannelTypes} = require('../structures/types'); + +module.exports = /** @param {message} message */ async (message) => { + if (message.type == messageChannelTypes.DM) { + const embd = new Embed() + .setTitle("hello world") + .setDescription("dkjhfslkjdfhjldsjhfkzdjhflkdsjhfdsjhfkdsjf"); + + const response = await message.channel.send({ content: "FDJHKSJDFHLKJDSHFLKJSDHFKDSJHFD", embeds: [embd] }); + console.log(response); + await delay(2000); + + const response2 = await message.reply({content: `You said "${message.content}"!`, embeds: [embd]}); + console.log(response2); + await delay(2000); + + const response3 = await response.edit("KAT"); + console.log(response3); + } +} \ No newline at end of file diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 0000000..9cf09fc --- /dev/null +++ b/tests/test.js @@ -0,0 +1,37 @@ +const { Client, gateWayIntents, message, Interaction } = require('../structures/types'); +const { bottoken } = require('../config.json'); + + +var c = new Client({ + intents: [ + gateWayIntents.Guilds, + gateWayIntents.GuildMessages, + gateWayIntents.GuildMessageReactions, + gateWayIntents.GuildVoiceStates, + gateWayIntents.GuildEmojisAndStickers, + gateWayIntents.GuildPresences, + gateWayIntents.GuildMembers, + gateWayIntents.DirectMessages, + gateWayIntents.DirectMessageReactions, + gateWayIntents.DirectMessageTyping, + gateWayIntents.MessageContent + ] +}); + + +c.login(bottoken); + + +c.on('messageRecieved', /**@param {message} message*/ async (message) => { + require('./messageTests.js')(message); +}); + + +c.on('interactionRecieved', /** @param {Interaction} interaction*/ async (interaction) => { + require('./interactionTests.js')(interaction); +}); + + +c.on('ready', () => { + console.log("BOT ONLINE!"); +}); \ No newline at end of file