2023-04-01 21:49:27 -04:00
|
|
|
import gateWayEvents from '../gateway/dispatch.js';
|
|
|
|
|
//import WebSocketClient from 'websocket';
|
|
|
|
|
//import WebSocketConnection from 'websocket';
|
|
|
|
|
import WebSocket from 'ws';
|
|
|
|
|
import handleResponses from './handleEvents.js';
|
|
|
|
|
import { EventEmitter } from 'events';
|
|
|
|
|
import axios from 'axios';
|
|
|
|
|
import { exit } from 'process';
|
|
|
|
|
import Guild from '../guilds/Guild.js';
|
2023-04-02 09:49:47 -04:00
|
|
|
import user from '../messages/User.js';
|
2023-04-07 19:13:15 -04:00
|
|
|
import { Thread } from '../guilds/ThreadManager.js';
|
2023-04-18 16:50:15 -04:00
|
|
|
import { InteractionManager } from '../interactions/InteractionManager.js';
|
|
|
|
|
import { Interaction } from '../interactions/interaction.js';
|
2023-03-18 18:02:17 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
export class Client extends EventEmitter {
|
|
|
|
|
/** @type {WebSocket} */
|
2023-03-18 18:02:17 -04:00
|
|
|
ws;
|
|
|
|
|
|
|
|
|
|
/** @type {Number} */
|
|
|
|
|
heartBeatInterval;
|
|
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
/** @type {gateWayEvents[]} */
|
2023-03-18 18:02:17 -04:00
|
|
|
gwintents;
|
|
|
|
|
|
|
|
|
|
/** @type {String} */
|
|
|
|
|
#token;
|
2023-03-19 18:02:21 -04:00
|
|
|
|
|
|
|
|
/** @type {String} */
|
|
|
|
|
id;
|
2023-03-18 18:02:17 -04:00
|
|
|
|
|
|
|
|
/** @type {WebSocketConnection}*/
|
|
|
|
|
connection;
|
|
|
|
|
|
|
|
|
|
/** @type {Object} */
|
|
|
|
|
user_settings;
|
|
|
|
|
|
|
|
|
|
/** @type {Object} */
|
|
|
|
|
user_profile;
|
|
|
|
|
|
2023-03-24 20:32:27 -04:00
|
|
|
/** @type {Map<String, Guild>} */
|
|
|
|
|
guilds;
|
|
|
|
|
|
2023-04-07 19:13:15 -04:00
|
|
|
/** @type {import('axios').AxiosInstance} */
|
|
|
|
|
axiosCustom;
|
2023-03-18 18:02:17 -04:00
|
|
|
|
2023-04-18 16:50:15 -04:00
|
|
|
/** @type {InteractionManager} */
|
|
|
|
|
commands;
|
|
|
|
|
|
2023-03-18 18:02:17 -04:00
|
|
|
/**
|
|
|
|
|
* @param {opts} input
|
|
|
|
|
*/
|
|
|
|
|
constructor(input) {
|
|
|
|
|
super();
|
|
|
|
|
this.gwintents = input.intents;
|
2023-03-24 20:32:27 -04:00
|
|
|
this.guilds = new Map();
|
2023-03-18 18:02:17 -04:00
|
|
|
}
|
|
|
|
|
|
2023-03-20 12:45:20 -04:00
|
|
|
async #heartbeat(hbInt, hbSequence) {
|
|
|
|
|
const toSend = JSON.stringify({ op: 1, d: 0 });
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws.send((toSend));
|
2023-03-20 12:45:20 -04:00
|
|
|
|
|
|
|
|
setInterval(() => {
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws.send(toSend);
|
2023-03-20 12:45:20 -04:00
|
|
|
}, hbInt);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-18 18:02:17 -04:00
|
|
|
/**
|
|
|
|
|
* @param {Number} hbint
|
|
|
|
|
*/
|
|
|
|
|
async #startHeartBeat(hbint)
|
|
|
|
|
{
|
|
|
|
|
this.heartBeatInterval = hbint;
|
|
|
|
|
console.log("INTERVAL SET TO: " + this.heartBeatInterval);
|
2023-03-20 12:45:20 -04:00
|
|
|
this.#heartbeat(hbint);
|
2023-03-18 18:02:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-03-24 20:32:27 -04:00
|
|
|
//#region Event Emitters
|
2023-03-18 18:02:17 -04:00
|
|
|
messageRecieved(msg) {
|
|
|
|
|
this.emit("messageRecieved", msg);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-18 16:50:15 -04:00
|
|
|
async ready(response) {
|
2023-04-07 19:13:15 -04:00
|
|
|
this.user_profile = response.profile;
|
|
|
|
|
this.user_settings = response.config;
|
|
|
|
|
this.id = response.profile.id;
|
2023-04-18 16:50:15 -04:00
|
|
|
|
|
|
|
|
const commandsRaw = (await this.axiosCustom.get(`applications/${this.id}/commands`)).data;
|
|
|
|
|
this.commands = new InteractionManager(commandsRaw, this);
|
2023-03-18 18:02:17 -04:00
|
|
|
this.emit('ready');
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-07 19:13:15 -04:00
|
|
|
customError(err) { this.emit('error', err); }
|
2023-03-18 18:02:17 -04:00
|
|
|
|
2023-04-07 19:13:15 -04:00
|
|
|
interactionRecieved(data, response) {
|
|
|
|
|
if (data["d"]["member"] && data["d"]["member"]["id"] != this.user_profile.id) {
|
|
|
|
|
response.interaction.guild = this.guilds.get(response.interaction.guild_id);
|
|
|
|
|
response.interaction.user = new user(data["d"]["member"]["user"]);
|
|
|
|
|
this.emit('interactionRecieved', response.interaction);
|
|
|
|
|
}
|
|
|
|
|
else if (data["d"]["user"]["id"] != this.user_profile.id) {
|
|
|
|
|
this.emit('interactionRecieved', response.interaction);
|
|
|
|
|
}
|
2023-03-20 12:45:20 -04:00
|
|
|
}
|
2023-03-18 18:02:17 -04:00
|
|
|
|
2023-03-24 20:32:27 -04:00
|
|
|
/**
|
|
|
|
|
* @param {Guild} guild
|
|
|
|
|
*/
|
|
|
|
|
guildCreate(guild) {
|
|
|
|
|
if (!this.guilds.has(guild.id)) {
|
|
|
|
|
this.guilds.set(guild.id, guild);
|
|
|
|
|
this.emit('guildCreate', guild);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guildDelete(guild) {
|
|
|
|
|
this.emit('guildDelete', guild);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guildMemberAdd(member) {
|
|
|
|
|
this.emit('guildMemberAdd', member);
|
|
|
|
|
}
|
2023-04-07 19:13:15 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
threadCreate(threadRaw) {
|
|
|
|
|
const guild = this.guilds.get(threadRaw.guild_id);
|
|
|
|
|
const newThread = new Thread(threadRaw, guild, this.#token);
|
|
|
|
|
guild.threads.cache.set(newThread.id, newThread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
threadEdit(threadRaw) {
|
|
|
|
|
if (!this.guilds.has(threadRaw.guild_id)) return;
|
|
|
|
|
const guild = this.guilds.get(threadRaw.guild_id);
|
|
|
|
|
|
|
|
|
|
if (!guild.threads.cache.has(threadRaw.id)) return;
|
|
|
|
|
console.log(threadRaw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThreadDelete(threadRaw) {
|
|
|
|
|
if (!this.guilds.has(threadRaw.guild_id)) return;
|
|
|
|
|
const guild = this.guilds.get(threadRaw.guild_id);
|
|
|
|
|
|
|
|
|
|
if (!guild.threads.cache.has(threadRaw.id)) return;
|
|
|
|
|
guild.threads.cache.delete()
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-24 20:32:27 -04:00
|
|
|
//#endregion
|
|
|
|
|
|
|
|
|
|
|
2023-03-18 18:02:17 -04:00
|
|
|
/**
|
|
|
|
|
* @param {String} token
|
|
|
|
|
*/
|
2023-03-19 18:02:21 -04:00
|
|
|
async login(token, isUser = false) {
|
|
|
|
|
if (!isUser) token = "Bot " + token;
|
2023-04-07 19:13:15 -04:00
|
|
|
this.axiosCustom = axios.create({
|
|
|
|
|
baseURL: "https://discord.com/api/",
|
2023-04-07 20:12:16 -04:00
|
|
|
headers: { Authorization: token }
|
2023-04-07 19:13:15 -04:00
|
|
|
});
|
2023-04-08 16:33:58 -04:00
|
|
|
|
|
|
|
|
this.axiosCustom.interceptors.response.use((response) => {
|
|
|
|
|
return response;
|
|
|
|
|
}, function (err) {
|
2023-04-25 17:34:01 -04:00
|
|
|
console.log(err.response.data);
|
|
|
|
|
throw `REQUEST FAILED WITH STATUS CODE ${err.response.status} AND REASON "${JSON.stringify(err.response.data)}"`;
|
2023-04-08 16:33:58 -04:00
|
|
|
});
|
2023-03-19 18:02:21 -04:00
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws = new WebSocket("wss://gateway.discord.gg/?v=10&encoding=json");
|
2023-03-19 18:02:21 -04:00
|
|
|
this.#token = token;
|
|
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws.on('open', () => {
|
|
|
|
|
//Get the user intents
|
|
|
|
|
let iCount = 0;
|
|
|
|
|
for (let i of this.gwintents) {
|
|
|
|
|
iCount += (i) ? i : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var idObj = {
|
|
|
|
|
op: 2,
|
|
|
|
|
d: {
|
|
|
|
|
token: token.replace("Bot ", ""),
|
|
|
|
|
intents: iCount, //61440,
|
|
|
|
|
properties: {
|
|
|
|
|
os: "linux",
|
|
|
|
|
browser: "ion_",
|
|
|
|
|
device: "my_library"
|
2023-03-19 18:02:21 -04:00
|
|
|
}
|
2023-04-01 21:49:27 -04:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.ws.send(JSON.stringify(idObj));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.ws.on('message', async (msg) => {
|
|
|
|
|
const data = JSON.parse(msg.toString());
|
2023-04-07 20:12:16 -04:00
|
|
|
const response = await handleResponses(data, token, this);
|
2023-04-01 21:49:27 -04:00
|
|
|
|
2023-04-07 19:13:15 -04:00
|
|
|
if (response.op == 10) { return this.#startHeartBeat(response.heartBeat, token); }
|
|
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
else if (response.op == 0) {
|
2023-04-07 19:13:15 -04:00
|
|
|
switch(response.t) {
|
|
|
|
|
case gateWayEvents.Ready: this.ready(response);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.MessageCreate:
|
|
|
|
|
if (data["d"]["author"]["id"] != this.user_profile.id){
|
|
|
|
|
response.message.guild = this.guilds.get(response.message.guild_id);
|
|
|
|
|
this.messageRecieved(response.message);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.InteractionCreate: this.interactionRecieved(data, response);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.GuildCreate: this.guildCreate(response.guild);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.GuildDelete: this.guildDelete(response.guild);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.GuildMemberAdd: this.guildMemberAdd(response.member);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.ThreadCreate: this.threadCreate(response.threadRaw);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.ThreadUpdate: this.threadEdit(response.threadRaw);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case gateWayEvents.ThreadDelete: this.ThreadDelete(response.threadRaw);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: // console.log(response.t);
|
2023-03-18 18:02:17 -04:00
|
|
|
}
|
2023-04-01 21:49:27 -04:00
|
|
|
} else {
|
2023-04-04 22:06:12 -04:00
|
|
|
// commmented to avoid heartbeats
|
|
|
|
|
// console.log(response.t);
|
2023-04-01 21:49:27 -04:00
|
|
|
}
|
|
|
|
|
});
|
2023-03-18 18:02:17 -04:00
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws.on('close', (code, desc) => {
|
|
|
|
|
console.log(`CONNECTION CLOSED WITH CODE ${code}\nREASON:\n ${desc}`);
|
|
|
|
|
exit(1);
|
2023-03-19 18:02:21 -04:00
|
|
|
});
|
2023-03-18 18:02:17 -04:00
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws.on('error', (err) => {
|
|
|
|
|
reject(err);
|
|
|
|
|
});
|
2023-03-19 18:02:21 -04:00
|
|
|
|
2023-04-01 21:49:27 -04:00
|
|
|
this.ws.on('error', (err) => { reject(err); });
|
2023-03-19 18:02:21 -04:00
|
|
|
});
|
2023-03-18 18:02:17 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//All client properties will be re-routed through this export
|
2023-04-01 21:49:27 -04:00
|
|
|
export {gateWayIntents} from '../gateway/intents.js';
|