Added message reply, embeds, and bot login capabilities

This commit is contained in:
ION606
2023-03-19 18:02:21 -04:00
parent 35b993b3fe
commit 9faf4a315e
9 changed files with 422 additions and 55 deletions
+45 -30
View File
@@ -5,6 +5,7 @@ var WebSocketClient = require('websocket').client;
const WebSocketConnection = require('websocket').connection;
const handleResponses = require('./handleEvents.js');
const { EventEmitter } = require('events');
const axios = require('axios');
@@ -20,6 +21,9 @@ class Client extends EventEmitter {
/** @type {String} */
#token;
/** @type {String} */
id;
/** @type {WebSocketConnection}*/
connection;
@@ -56,8 +60,8 @@ class Client extends EventEmitter {
var idObj = {
op: 2,
d: {
token: this.#token,
intents: this.gwintents.value, //61440,
token: this.#token.replace("Bot ", ""),
intents: iCount, //61440,
properties: {
os: "linux",
browser: "ion_",
@@ -86,42 +90,53 @@ class Client extends EventEmitter {
/**
* @param {String} token
*/
async login(token) {
this.ws = new WebSocketClient({maxReceivedFrameSize: Infinity});
this.#token = token;
async login(token, isUser = false) {
if (!isUser) token = "Bot " + token;
return new Promise((resolve, reject) => {
this.ws = new WebSocketClient({maxReceivedFrameSize: Infinity});
this.#token = token;
this.ws.on('connect', async (connection) => {
connection.on('message', async (msg) => {
const data = JSON.parse(msg.utf8Data);
this.ws.on('connect', async (connection) => {
connection.on('message', async (msg) => {
const data = JSON.parse(msg.utf8Data);
const response = await handleResponses(data);
const response = await handleResponses(data, token);
if (response.op == 10) { this.#startHeartBeat(response.heartBeat, token); }
else if (response.op == 0) {
if (response.t == gateWayEvents.Ready) {
this.user_profile = response.profile;
this.user_settings = response.config;
this.ready();
if (response.op == 10) { this.#startHeartBeat(response.heartBeat, token); }
else if (response.op == 0) {
if (response.t == gateWayEvents.Ready) {
this.user_profile = response.profile;
this.user_settings = response.config;
this.id = response.profile.id;
this.ready();
}
else if (response.t == gateWayEvents.MessageCreate) {
if (data["d"]["author"]["id"] != this.user_profile.id){
this.messageRecieved(response.message);
}
}
else console.log(response.t);
} else {
console.log(response.t);
}
else if (response.t == gateWayEvents.MessageCreate) {
this.messageRecieved(response.message);
}
else console.log(response.t);
} else {
console.log(response.t);
}
});
connection.on('close', (code, desc) => {
console.log(`CONNECTION CLOSED WITH CODE ${code}\nREASON:\n ${desc}`);
});
connection.on('error', (err) => {
reject(err);
});
this.connection = connection;
});
connection.on('close', (code, desc) => {
console.log(`CONNECTION CLOSED WITH CODE ${code}\nREASON:\n ${desc}`);
});
this.ws.on('connectFailed', (err) => { reject(err); });
this.connection = connection;
this.ws.connect("wss://gateway.discord.gg/?v=10&encoding=json");
});
this.ws.on('connectFailed', (err) => { console.error(err); })
this.ws.connect("wss://gateway.discord.gg/?v=10&encoding=json");
}
}
+2 -2
View File
@@ -8,7 +8,7 @@ const { message } = require('../messages/message.js');
* @param {Object} msg
* @returns {Promise<Boolean>}
*/
module.exports = async function handleEvents(msgObj) {
module.exports = async function handleEvents(msgObj, token) {
return new Promise((resolve, reject) => {
const op = msgObj["op"];
const t = msgObj["t"];
@@ -18,7 +18,7 @@ module.exports = async function handleEvents(msgObj) {
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) {
const msg = new message(msgObj["d"]);
const msg = new message(msgObj["d"], token);
resolve({op: op, t: t, message: msg});
}
-17
View File
@@ -1,17 +0,0 @@
const axios = require("axios").create({baseUrl: "https://jsonplaceholder.typicode.com/"});
class Channel {
/** @type {String} */
id;
/**
* @param {Object} inp
*/
async send(inp) {
const toSend = (typeof inp == 'string') ? {content: inp} : inp;
const response = axios.post(`${id}/messages`, {
// Authorization:
});
}
}
+37
View File
@@ -0,0 +1,37 @@
class msgAuthor {
/** @type {String} */
id;
/** @type {String} */
username;
/** @type {String} */
global_name;
/** @type {String} */
display_name;
/** @type {String} */
avatar;
/** @type {String} */
avatar_decoration;
/** @type {String} */
discriminator;
/** @type {Number} */
public_flags;
constructor(obj) {
for (const k in this) {
if (obj[k]) {
this[k] = obj[k];
}
}
}
}
module.exports = msgAuthor;
+127
View File
@@ -0,0 +1,127 @@
const colConvert = require('../../utils/color_functions.js');
class Embed {
/** @type {Number} */
color;
/** @type {String} */
title;
/** @type {String} */
description;
/** @type {String} */
url;
/** @type {{name: String, iconUrl: String, url: String}} */
author;
/** @type {[{name: String, value: String, inline?: Boolean}]} */
fields;
/** @type {String} */
image;
/** @type {String} */
thumbnail;
/** @type {Boolean} */
attatchTimeStamp;
/** @type {{text: String, iconUrl: String}} */
footer;
//#region Setters
/**
* @param {String} colorStr
*/
setColor(colorStr) {
this.color = colConvert(colorStr);
return this;
}
/**
* @param {String} title
*/
setTitle(title) {
this.title = title;
return this;
}
/**
* @param {String} desc
*/
setDescription(desc) {
this.description = desc;
return this;
}
/**
* @param {String} url
*/
setUr(url) {
this.url = url;
return this;
}
/**
* @param {{name: String, iconUrl: String, url: String}} author
*/
setAuthor(author) {
this.author = author;
return this;
}
/**
* @param {[{name: String, value: String, inline?: Boolean}]} fields
*/
setFields(fields) {
this.fields = fields;
return this;
}
/**
* @param {String} url
*/
setImage(url) {
this.image = url;
return this;
}
/**
* @param {String} url
*/
setThumbnail(url) {
this.thumbnail = url;
return this;
}
setTimeStamp() {
this.attatchTimeStamp = !this.attatchTimeStamp;
return this;
}
/**
* @param {{text: String, iconUrl: String}} footer
*/
setFooter(footer) {
this.footer = footer;
return this;
}
/**
* @returns {Object}
*/
toJSON() {
var retObj = {};
for (const k in this) {
if (this[k] != undefined) retObj[k] = this[k];
}
return retObj;
}
//#endregion
}
module.exports = Embed;
+148 -6
View File
@@ -1,10 +1,56 @@
const messageChannelTypes = require('./messageChannelTypes.js');
const author = require('./author.js');
const axios = require('axios');
const Embed = require('./embed');
class Channel {
/** @type {String} */
id;
/** @type {String} */
#token;
constructor(token, id) {
this.#token = token;
this.id = id;
}
/**
* @param {Object} inp
* @returns {message}
*/
async send(inp) {
return new Promise(async (resolve) => {
const toSend = (typeof inp == 'string') ? inp : inp.content;
const config = {
headers: {
Authorization: this.#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/channels/${this.id}/messages`, {
content: toSend,
message_reference: inp.message_reference || undefined,
embeds: embds
}, config);
resolve(new message(response.data, this.#token));
});
}
}
class message {
/** @type {Object} */
/** @type {author} */
author;
/** @type {Object} */
@@ -12,6 +58,21 @@ class message {
/** @type {Object[]} */
mentions;
/** @type {Object[]} */
mention_roles;
/** @type {Boolean} */
mention_everyone;
/** @type {message} */
referenced_message;
/** @type {String} */
timestamp;
/** @type {Boolean} */
pinned;
/** @type {Object} */
member;
@@ -25,26 +86,107 @@ class message {
/** @type {Object[]} */
attachments;
/** @type {Object[]} */
embeds;
/** @type {String} */
guild_id;
/** @type {Object} */
type;
/** @type {Channel} */
channel
/** @type {String} */
#token;
/**
* @param {String} content
* @returns {Promise<message>}
*/
reply(inp) {
return new Promise(async (resolve, reject) => {
const refObj = {
message_id: this.id,
channel_id: this.channel.id,
guild_id: this.guild_id,
fail_if_not_exists: false //when sending, whether to error if the referenced message doesn't exist instead of sending as a normal (non-reply) message, default true
}
const toSend = (typeof inp == 'string') ? {content: inp} : inp;
toSend['message_reference'] = refObj;
resolve(await this.channel.send(toSend));
});
}
delete() {
return new Promise(async (resolve, reject) => {
try {
const config = {
headers: {
Authorization: this.#token
}
}
const response = await axios.delete(`https://discord.com/api/channels/${this.channel.id}/messages/${this.id}`, config);
resolve(response.data);
} catch(err) {
reject(err);
}
})
}
/**
* @param {{content: String, embeds: [Object]} | String} inp
*/
async edit(inp) {
return new Promise(async (resolve, reject) => {
const newMsg = (typeof inp == "string") ? {content: inp} : inp;
const config = {
headers: {
Authorization: this.#token
}
}
axios.patch(`https://discord.com/api/channels/${this.channel.id}/messages/${this.id}`, newMsg, config).then((response) => {
resolve(response.data);
}).catch((err) => {
reject(`REQUEST FAILED WITH CODE ${err.response.data.code} AND THE FOLLOWING REASON:\n${err.response.data.message}`);
});
});
}
/**
* @param {Object} msgRaw
*/
constructor(msgRaw) {
constructor(msgRaw, token) {
this.#token = token;
for (const k in this) {
if (msgRaw[k] != undefined) {
if (k == 'type') {
this.type = (msgRaw['guild_id']) ? msgRaw[k] : 1;
} else {
}
else if (k == "author") {
this[k] = new author(msgRaw[k]);
}
else {
if (k == 'channel_id') {
this.channel = new Channel(this.#token, msgRaw[k]);
}
this[k] = msgRaw[k];
}
}
}
}
}
}
+7
View File
@@ -0,0 +1,7 @@
const {message} = require('./messages/message');
const {Client, gateWayIntents} = require('./client/client.js');
const Embed = require('./messages/embed');
const messageChannelTypes = require('./messages/messageChannelTypes');
module.exports = { message, Client, gateWayIntents, Embed, messageChannelTypes }
+24
View File
@@ -0,0 +1,24 @@
const Colors = require('./colors.js');
/**
* Resolves a ColorResolvable into a color number.
* @param {String} color Color to resolve
* @returns {Number} A color
*/
function resolveColor(color) {
if (typeof color === 'string') {
if (color === 'Random') return Math.floor(Math.random() * (0xffffff + 1));
if (color === 'Default') return 0;
color = Colors[color] ?? parseInt(color.replace('#', ''), 16);
} else if (Array.isArray(color)) {
color = (color[0] << 16) + (color[1] << 8) + color[2];
}
if (color < 0 || color > 0xffffff) throw new RangeError('COLOR_RANGE');
else if (Number.isNaN(color)) throw new TypeError('COLOR_CONVERT');
return color;
}
module.exports = resolveColor;
+32
View File
@@ -0,0 +1,32 @@
module.exports = {
Default: 0x000000,
White: 0xffffff,
Aqua: 0x1abc9c,
Green: 0x57f287,
Blue: 0x3498db,
Yellow: 0xfee75c,
Purple: 0x9b59b6,
LuminousVividPink: 0xe91e63,
Fuchsia: 0xeb459e,
Gold: 0xf1c40f,
Orange: 0xe67e22,
Red: 0xed4245,
Grey: 0x95a5a6,
Navy: 0x34495e,
DarkAqua: 0x11806a,
DarkGreen: 0x1f8b4c,
DarkBlue: 0x206694,
DarkPurple: 0x71368a,
DarkVividPink: 0xad1457,
DarkGold: 0xc27c0e,
DarkOrange: 0xa84300,
DarkRed: 0x992d22,
DarkGrey: 0x979c9f,
DarkerGrey: 0x7f8c8d,
LightGrey: 0xbcc0c0,
DarkNavy: 0x2c3e50,
Blurple: 0x5865f2,
Greyple: 0x99aab5,
DarkButNotBlack: 0x2c2f33,
NotQuiteBlack: 0x23272a,
};