From 299663adf80166e9117d9b827a90f621ba61946e Mon Sep 17 00:00:00 2001 From: Essem Date: Sun, 4 Jul 2021 23:15:27 -0500 Subject: [PATCH 1/8] Port to eris-fleet --- app.js | 36 ++++++--- classes/command.js | 3 +- classes/musicCommand.js | 2 +- commands/general/info.js | 4 +- commands/general/restart.js | 3 +- commands/general/stats.js | 10 +-- events/guildCreate.js | 4 +- events/guildDelete.js | 2 +- events/messageCreate.js | 4 +- events/rawWS.js | 2 +- events/voiceChannelLeave.js | 2 +- events/voiceChannelSwitch.js | 2 +- package-lock.json | 153 +++++------------------------------ package.json | 3 +- shard.js | 110 +++++++++++-------------- utils/collections.js | 4 +- utils/logger.js | 2 +- 17 files changed, 115 insertions(+), 231 deletions(-) diff --git a/app.js b/app.js index 01e5eee..8463187 100644 --- a/app.js +++ b/app.js @@ -6,14 +6,23 @@ The bot will continue to run past this message, but keep in mind that it could b require("dotenv").config(); // main sharding manager -const { Master } = require("eris-sharder"); +const { Fleet } = require("eris-fleet"); +const { isMaster } = require("cluster"); +const path = require("path"); +const { inspect } = require("util"); // dbl posting const TopGG = require("@top-gg/sdk"); const dbl = process.env.NODE_ENV === "production" && process.env.DBL !== "" ? new TopGG.Api(process.env.DBL) : null; -const master = new Master(`Bot ${process.env.TOKEN}`, "/shard.js", { - name: "esmBot", - stats: true, +const Admiral = new Fleet({ + path: path.join(__dirname, "./shard.js"), + token: `Bot ${process.env.TOKEN}`, + startingStatus: { + status: "idle", + game: { + name: "Starting esmBot..." + } + }, clientOptions: { disableEvents: { CHANNEL_DELETE: true, @@ -48,13 +57,18 @@ const master = new Master(`Bot ${process.env.TOKEN}`, "/shard.js", { } }); -master.on("stats", async (stats) => { - master.broadcast(0, Object.assign(stats, { _eventName: "stat" })); - // dbl posting +if (isMaster) { + Admiral.on("log", (m) => console.log(m)); + Admiral.on("debug", (m) => console.debug(m)); + Admiral.on("warn", (m) => console.warn(m)); + Admiral.on("error", (m) => console.error(inspect(m))); + if (dbl) { - await dbl.postStats({ - serverCount: stats.guilds, - shardCount: await master.calculateShards() + Admiral.on("stats", async (m) => { + await dbl.postStats({ + serverCount: m.guilds, + shardCount: m.shardCount + }); }); } -}); \ No newline at end of file +} \ No newline at end of file diff --git a/classes/command.js b/classes/command.js index 1dcec6f..7ce48e4 100644 --- a/classes/command.js +++ b/classes/command.js @@ -1,7 +1,8 @@ class Command { - constructor(client, cluster, ipc, message, args, content, specialArgs) { + constructor(client, cluster, worker, ipc, message, args, content, specialArgs) { this.client = client; this.cluster = cluster; + this.worker = worker; this.ipc = ipc; this.message = message; this.args = args; diff --git a/classes/musicCommand.js b/classes/musicCommand.js index 0ff03ea..98ec336 100644 --- a/classes/musicCommand.js +++ b/classes/musicCommand.js @@ -2,7 +2,7 @@ const Command = require("./command.js"); const soundPlayer = require("../utils/soundplayer.js"); class MusicCommand extends Command { - constructor(client, cluster, ipc, message, args, content, specialArgs) { + constructor(client, cluster, worker, ipc, message, args, content, specialArgs) { super(client, cluster, ipc, message, args, content, specialArgs); this.connection = soundPlayer.players.get(message.channel.guild.id); } diff --git a/commands/general/info.js b/commands/general/info.js index 1320d27..8c16822 100644 --- a/commands/general/info.js +++ b/commands/general/info.js @@ -1,10 +1,10 @@ const { version } = require("../../package.json"); -const collections = require("../../utils/collections.js"); const Command = require("../../classes/command.js"); class InfoCommand extends Command { async run() { const owner = await this.ipc.fetchUser(process.env.OWNER); + const stats = await this.ipc.getStats(); return { "embed": { "color": 16711680, @@ -23,7 +23,7 @@ class InfoCommand extends Command { }, { "name": "💬 Total Servers:", - "value": collections.stats.guilds ? collections.stats.guilds : `${this.client.guilds.size} (for this cluster only)` + "value": stats.guilds ? stats.guilds : `${this.client.guilds.size} (for this cluster only)` }, { "name": "✅ Official Server:", diff --git a/commands/general/restart.js b/commands/general/restart.js index 7b767ef..d4b7e27 100644 --- a/commands/general/restart.js +++ b/commands/general/restart.js @@ -11,7 +11,8 @@ class RestartCommand extends Command { for (const command of collections.commands) { await handler.unload(command); } - this.ipc.broadcast("restart"); + this.ipc.restartAllClusters(); + //this.ipc.broadcast("restart"); } static description = "Restarts me"; diff --git a/commands/general/stats.js b/commands/general/stats.js index b55176c..7720783 100644 --- a/commands/general/stats.js +++ b/commands/general/stats.js @@ -1,5 +1,4 @@ const { version } = require("../../package.json"); -const collections = require("../../utils/collections.js"); const day = require("dayjs"); day.extend(require("dayjs/plugin/duration")); const os = require("os"); @@ -10,6 +9,7 @@ class StatsCommand extends Command { const duration = day.duration(this.client.uptime).format(" D [days], H [hrs], m [mins], s [secs]"); const uptime = day.duration(process.uptime(), "seconds").format(" D [days], H [hrs], m [mins], s [secs]"); const owner = await this.ipc.fetchUser(process.env.OWNER); + const stats = await this.ipc.getStats(); return { embed: { "author": { @@ -24,12 +24,12 @@ class StatsCommand extends Command { }, { "name": "Cluster Memory Usage", - "value": `${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB`, + "value": `${stats.clusters[this.cluster].ram.toFixed(2)} MB`, "inline": true }, { "name": "Total Memory Usage", - "value": collections.stats.totalRam ? `${collections.stats.totalRam.toFixed(2)} MB` : "Unknown", + "value": stats.totalRam ? `${stats.totalRam.toFixed(2)} MB` : "Unknown", "inline": true }, { @@ -66,12 +66,12 @@ class StatsCommand extends Command { }, { "name": "Servers", - "value": collections.stats.guilds ? collections.stats.guilds : `${this.client.guilds.size} (for this cluster only)`, + "value": stats.guilds ? stats.guilds : `${this.client.guilds.size} (for this cluster only)`, "inline": true }, { "name": "Users (approximation)", - "value": collections.stats.users ? collections.stats.users : `${this.client.users.size} (for this cluster only)`, + "value": stats.users ? stats.users : `${this.client.users.size} (for this cluster only)`, "inline": true } ] diff --git a/events/guildCreate.js b/events/guildCreate.js index ff4070b..b33e8e2 100644 --- a/events/guildCreate.js +++ b/events/guildCreate.js @@ -2,7 +2,7 @@ const db = require("../utils/database.js"); const logger = require("../utils/logger.js"); // run when the bot is added to a guild -module.exports = async (client, cluster, ipc, guild) => { - logger.log("info", `[GUILD JOIN] ${guild.name} (${guild.id}) added the bot.`); +module.exports = async (client, cluster, worker, ipc, guild) => { + logger.log(`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot.`); await db.addGuild(guild); }; diff --git a/events/guildDelete.js b/events/guildDelete.js index 4e38a14..40a43f2 100644 --- a/events/guildDelete.js +++ b/events/guildDelete.js @@ -1,6 +1,6 @@ const logger = require("../utils/logger.js"); // run when the bot is removed from a guild -module.exports = async (client, cluster, ipc, guild) => { +module.exports = async (client, cluster, worker, ipc, guild) => { logger.log(`[GUILD LEAVE] ${guild.name} (${guild.id}) removed the bot.`); }; diff --git a/events/messageCreate.js b/events/messageCreate.js index d812240..5ff5630 100644 --- a/events/messageCreate.js +++ b/events/messageCreate.js @@ -5,7 +5,7 @@ const collections = require("../utils/collections.js"); const parseCommand = require("../utils/parseCommand.js"); // run when someone sends a message -module.exports = async (client, cluster, ipc, message) => { +module.exports = async (client, cluster, worker, ipc, message) => { // ignore dms and other bots if (message.author.bot) return; @@ -88,7 +88,7 @@ module.exports = async (client, cluster, ipc, message) => { await database.addCount(collections.aliases.has(command) ? collections.aliases.get(command) : command); const startTime = new Date(); // eslint-disable-next-line no-unused-vars - const commandClass = new cmd(client, cluster, ipc, message, parsed._, message.content.substring(prefix.length).trim().replace(command, "").trim(), (({ _, ...o }) => o)(parsed)); // we also provide the message content as a parameter for cases where we need more accuracy + const commandClass = new cmd(client, cluster, worker, ipc, message, parsed._, message.content.substring(prefix.length).trim().replace(command, "").trim(), (({ _, ...o }) => o)(parsed)); // we also provide the message content as a parameter for cases where we need more accuracy const result = await commandClass.run(); const endTime = new Date(); if ((endTime - startTime) >= 180000) reference.allowedMentions.repliedUser = true; diff --git a/events/rawWS.js b/events/rawWS.js index 65e55de..42d5001 100644 --- a/events/rawWS.js +++ b/events/rawWS.js @@ -1,7 +1,7 @@ const player = require("../utils/soundplayer.js"); // run when a raw packet is sent, used for sending data to lavalink -module.exports = async (client, cluster, ipc, packet) => { +module.exports = async (client, cluster, worker, ipc, packet) => { if (!player.manager) return; switch (packet.t) { case "VOICE_SERVER_UPDATE": diff --git a/events/voiceChannelLeave.js b/events/voiceChannelLeave.js index c477250..df8b365 100644 --- a/events/voiceChannelLeave.js +++ b/events/voiceChannelLeave.js @@ -2,7 +2,7 @@ const soundPlayer = require("../utils/soundplayer.js"); const AwaitRejoin = require("../utils/awaitrejoin.js"); const { random } = require("../utils/misc.js"); -module.exports = async (client, cluster, ipc, member, oldChannel) => { +module.exports = async (client, cluster, worker, ipc, member, oldChannel) => { const connection = soundPlayer.players.get(oldChannel.guild.id); if (connection && connection.type === "music" && oldChannel.id === connection.voiceChannel.id) { if (oldChannel.voiceMembers.filter((i) => i.id !== client.user.id).length === 0) { diff --git a/events/voiceChannelSwitch.js b/events/voiceChannelSwitch.js index 52067d4..7977894 100644 --- a/events/voiceChannelSwitch.js +++ b/events/voiceChannelSwitch.js @@ -1,5 +1,5 @@ const leaveHandler = require("./voiceChannelLeave.js"); -module.exports = async (client, cluster, ipc, member, newChannel, oldChannel) => { +module.exports = async (client, cluster, worker, ipc, member, newChannel, oldChannel) => { await leaveHandler(client, cluster, ipc, member, oldChannel); }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 070450d..122607c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "dayjs": "^1.10.4", "dotenv": "^9.0.2", "emoji-regex": "^9.2.2", - "eris-sharder": "github:esmBot/eris-sharder#eris-dev", + "eris": "^0.15.1", + "eris-fleet": "^0.3.7", "file-type": "^16.1.0", "jsqr": "^1.3.1", "lavacord": "^1.1.9", @@ -596,17 +597,6 @@ "node": ">=6" } }, - "node_modules/ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -626,14 +616,6 @@ "node": ">=4" } }, - "node_modules/ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -990,14 +972,6 @@ "simple-swizzle": "^0.2.2" } }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", @@ -1005,14 +979,6 @@ "dev": true, "peer": true }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1213,9 +1179,9 @@ } }, "node_modules/eris": { - "version": "0.15.2-dev", - "resolved": "git+ssh://git@github.com/abalabahaha/eris.git#ea9d6700c8e3fedf5d966da4babe195c8cd681da", - "license": "MIT", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/eris/-/eris-0.15.1.tgz", + "integrity": "sha512-IQ3BPW6OjgFoqjdh+irPOa1jFlkotk+WNu2GQQ7QAQfbzQEPZgn+F+hpOxfMUXPHOZMX4sPKLkVDkMHAssBYhw==", "dependencies": { "ws": "^7.2.1" }, @@ -1227,17 +1193,12 @@ "tweetnacl": "^1.0.1" } }, - "node_modules/eris-sharder": { - "version": "1.10.0", - "resolved": "git+ssh://git@github.com/esmBot/eris-sharder.git#3b7366e5d99012ca0e3350e4d81f384b48911c2d", - "license": "MIT", - "dependencies": { - "colors": "^1.1.2", - "eris": "github:abalabahaha/eris#dev", - "fancy-log": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" + "node_modules/eris-fleet": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eris-fleet/-/eris-fleet-0.3.7.tgz", + "integrity": "sha512-irrGAZIwTXWxIfsSoi8YIm0nHImUADKG+wSr7yk5QgJfSFzIpCEgqFr4x7hdskfcwRa4CCR2HUrjuWDc0zITvg==", + "peerDependencies": { + "eris": "^0.15.0" } }, "node_modules/erlpack": { @@ -1606,20 +1567,6 @@ "node": ">=6" } }, - "node_modules/fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2560,14 +2507,6 @@ "node": ">=6" } }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -3420,14 +3359,6 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "node_modules/time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -4219,14 +4150,6 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "requires": { - "ansi-wrap": "0.1.0" - } - }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -4240,11 +4163,6 @@ "color-convert": "^1.9.0" } }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" - }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -4520,11 +4438,6 @@ "simple-swizzle": "^0.2.2" } }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - }, "colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", @@ -4532,11 +4445,6 @@ "dev": true, "peer": true }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4690,22 +4598,20 @@ } }, "eris": { - "version": "git+ssh://git@github.com/abalabahaha/eris.git#ea9d6700c8e3fedf5d966da4babe195c8cd681da", - "from": "eris@github:abalabahaha/eris#dev", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/eris/-/eris-0.15.1.tgz", + "integrity": "sha512-IQ3BPW6OjgFoqjdh+irPOa1jFlkotk+WNu2GQQ7QAQfbzQEPZgn+F+hpOxfMUXPHOZMX4sPKLkVDkMHAssBYhw==", "requires": { "opusscript": "^0.0.8", "tweetnacl": "^1.0.1", "ws": "^7.2.1" } }, - "eris-sharder": { - "version": "git+ssh://git@github.com/esmBot/eris-sharder.git#3b7366e5d99012ca0e3350e4d81f384b48911c2d", - "from": "eris-sharder@github:esmBot/eris-sharder#eris-dev", - "requires": { - "colors": "^1.1.2", - "eris": "github:abalabahaha/eris#dev", - "fancy-log": "^1.3.0" - } + "eris-fleet": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eris-fleet/-/eris-fleet-0.3.7.tgz", + "integrity": "sha512-irrGAZIwTXWxIfsSoi8YIm0nHImUADKG+wSr7yk5QgJfSFzIpCEgqFr4x7hdskfcwRa4CCR2HUrjuWDc0zITvg==", + "requires": {} }, "erlpack": { "version": "git+ssh://git@github.com/abalabahaha/erlpack.git#5d0064f9e106841e1eead711a6451f99b0d289fd", @@ -4975,17 +4881,6 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5701,11 +5596,6 @@ "callsites": "^3.0.0" } }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -6366,11 +6256,6 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/package.json b/package.json index a58e34a..64b9baa 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "dayjs": "^1.10.4", "dotenv": "^9.0.2", "emoji-regex": "^9.2.2", - "eris-sharder": "github:esmBot/eris-sharder#eris-dev", + "eris": "^0.15.1", + "eris-fleet": "^0.3.7", "file-type": "^16.1.0", "jsqr": "^1.3.1", "lavacord": "^1.1.9", diff --git a/shard.js b/shard.js index ab7a0ff..92ddb8a 100644 --- a/shard.js +++ b/shard.js @@ -1,5 +1,5 @@ // shard base -const { Base } = require("eris-sharder"); +const { BaseClusterWorker } = require("eris-fleet"); // path stuff const { readdir } = require("fs").promises; // fancy loggings @@ -23,9 +23,11 @@ const helpGenerator = process.env.OUTPUT !== "" ? require("./utils/help.js") : null; const http = require("http"); -class Shard extends Base { +class Shard extends BaseClusterWorker { constructor(bot) { super(bot); + + this.init(); } async init() { @@ -48,7 +50,7 @@ class Shard extends Base { logger.log("log", `Loading event from ${file}...`); const eventName = file.split(".")[0]; const event = require(`./events/${file}`); - this.bot.on(eventName, event.bind(null, this.bot, this.clusterID, this.ipc)); + this.bot.on(eventName, event.bind(null, this.bot, this.clusterID, this.workerID, this.ipc)); } // connect to image api if enabled @@ -106,20 +108,40 @@ connected_workers ${image.connections.size} }); } - // handle process stop - process.on("SIGINT", () => { - logger.log("warn", "SIGINT detected, shutting down..."); - this.bot.editStatus("dnd", { - name: "Restarting/shutting down..." - }); - for (const command in collections.commands) { - handler.unload(command); - } - this.bot.disconnect(); - require("./utils/database.js").stop(); - process.exit(0); + this.ipc.register("reload", async (message) => { + const result = await handler.unload(message.cmd); + if (result) return this.ipc.broadcast("reloadFail", { result: result }); + const result2 = await handler.load(collections.paths.get(message.cmd)); + if (result2) return this.ipc.broadcast("reloadFail", { result: result2 }); + return this.ipc.broadcast("reloadSuccess"); }); - return; + + this.bot.privateChannels.limit = 0; + + this.ipc.register("soundreload", async () => { + const soundStatus = await sound.checkStatus(); + if (!soundStatus) { + const length = await sound.connect(this.bot); + return this.ipc.broadcast("soundReloadSuccess", { length }); + } else { + return this.ipc.broadcast("soundReloadFail"); + } + }); + + // connect to lavalink + if (!sound.status && !sound.connected) sound.connect(this.bot); + + database.setup(); + + // set activity (a.k.a. the gamer code) + (async function activityChanger() { + this.bot.editStatus("dnd", { + name: `${misc.random(messages)} | @${this.bot.user.username} help`, + }); + setTimeout(activityChanger.bind(this), 900000); + }).bind(this)(); + + logger.log("info", `Started worker ${this.workerID}.`); } async* getFiles(dir) { @@ -133,54 +155,16 @@ connected_workers ${image.connections.size} } } - async launch() { - await this.init(); - - this.ipc.register("stat", (message) => { - collections.stats = message; + shutdown(done) { + logger.log("warn", "SIGINT detected, shutting down..."); + this.bot.editStatus("dnd", { + name: "Restarting/shutting down..." }); - - this.ipc.register("restart", async () => { - this.bot.editStatus("dnd", { - name: "esmBot is restarting, please stand by." - }); - process.exit(1); - }); - - this.ipc.register("reload", async (message) => { - const result = await handler.unload(message.cmd); - if (result) return this.ipc.broadcast("reloadFail", { result: result }); - const result2 = await handler.load(collections.paths.get(message.cmd)); - if (result2) return this.ipc.broadcast("reloadFail", { result: result2 }); - return this.ipc.broadcast("reloadSuccess"); - }); - - this.ipc.register("soundreload", async () => { - const soundStatus = await sound.checkStatus(); - if (!soundStatus) { - const length = await sound.connect(this.bot); - return this.ipc.broadcast("soundReloadSuccess", { length }); - } else { - return this.ipc.broadcast("soundReloadFail"); - } - }); - - // connect to lavalink - if (!sound.status && !sound.connected) await sound.connect(this.bot); - - this.bot.privateChannels.limit = 0; - - await database.setup(); - - // set activity (a.k.a. the gamer code) - (async function activityChanger() { - this.bot.editStatus("dnd", { - name: `${misc.random(messages)} | @${this.bot.user.username} help`, - }); - setTimeout(activityChanger.bind(this), 900000); - }).bind(this)(); - - logger.log("info", `Started cluster ${this.clusterID}.`); + for (const command in collections.commands) { + handler.unload(command); + } + require("./utils/database.js").stop(); + done(); } } diff --git a/utils/collections.js b/utils/collections.js index 1eeeff2..177321a 100644 --- a/utils/collections.js +++ b/utils/collections.js @@ -27,6 +27,4 @@ class Cache extends Map { } exports.prefixCache = new Cache(); -exports.disabledCache = new Cache(); - -exports.stats = {}; \ No newline at end of file +exports.disabledCache = new Cache(); \ No newline at end of file diff --git a/utils/logger.js b/utils/logger.js index 1cdd451..6e5c799 100644 --- a/utils/logger.js +++ b/utils/logger.js @@ -1,4 +1,4 @@ -exports.log = (type, content) => content ? process.send({ name: type, msg: content }) : process.send({ name: "info", msg: type }); +exports.log = (type, content) => content ? process.send({ op: type, msg: content }) : process.send({ op: "info", msg: type }); exports.error = (...args) => this.log("error", ...args); From 736207075b78548769983dbbac2319b267045c0b Mon Sep 17 00:00:00 2001 From: Essem Date: Mon, 5 Jul 2021 08:14:52 -0500 Subject: [PATCH 2/8] winston is back, baby --- app.js | 76 ++++++++++- package-lock.json | 318 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 5 +- 3 files changed, 381 insertions(+), 18 deletions(-) diff --git a/app.js b/app.js index 8463187..75890b5 100644 --- a/app.js +++ b/app.js @@ -8,12 +8,40 @@ require("dotenv").config(); // main sharding manager const { Fleet } = require("eris-fleet"); const { isMaster } = require("cluster"); +// some utils const path = require("path"); -const { inspect } = require("util"); +const winston = require("winston"); // dbl posting const TopGG = require("@top-gg/sdk"); const dbl = process.env.NODE_ENV === "production" && process.env.DBL !== "" ? new TopGG.Api(process.env.DBL) : null; +if (isMaster) { + console.log(` + ,*\`$ z\`"v + F zBw\`% A ,W "W + ,\` ,EBBBWp"%. ,-=~~==-,+* 4BBE T + M BBBBBBBB* ,w=####Wpw 4BBBBB# 1 + F BBBBBBBMwBBBBBBBBBBBBB#wXBBBBBH E + F BBBBBBkBBBBBBBBBBBBBBBBBBBBE4BL k + # BFBBBBBBBBBBBBF" "RBBBW F + V ' 4BBBBBBBBBBM TBBL F + F BBBBBBBBBBF JBB L + F FBBBBBBBEB BBL 4 + E [BB4BBBBEBL BBL 4 + I #BBBBBBBEB 4BBH *w + A 4BBBBBBBBBEW, ,BBBB W [ +.A ,k 4BBBBBBBBBBBEBW####BBBBBBM BF F +k console.log(m)); - Admiral.on("debug", (m) => console.debug(m)); - Admiral.on("warn", (m) => console.warn(m)); - Admiral.on("error", (m) => console.error(inspect(m))); + const logger = winston.createLogger({ + levels: { + error: 0, + warn: 1, + info: 2, + main: 3, + debug: 4 + }, + transports: [ + new winston.transports.Console({ format: winston.format.colorize({ all: true }) }), + new winston.transports.File({ filename: "logs/error.log", level: "error" }), + new winston.transports.File({ filename: "logs/main.log" }) + ], + level: "main", + format: winston.format.combine( + winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), + winston.format.printf((info) => { + const { + timestamp, level, message, ...args + } = info; + + return `[${timestamp}]: [${level.toUpperCase()}] - ${message} ${Object.keys(args).length ? JSON.stringify(args, null, 2) : ""}`; + }), + ) + }); + + winston.addColors({ + info: "green", + main: "gray", + debug: "purple", + warn: "yellow", + error: "red" + }); + + Admiral.on("log", (m) => logger.main(m)); + Admiral.on("info", (m) => { + console.log("hi"); + logger.info(m); + }); + Admiral.on("debug", (m) => logger.debug(m)); + Admiral.on("warn", (m) => logger.warn(m)); + Admiral.on("error", (m) => logger.error(m)); if (dbl) { Admiral.on("stats", async (m) => { diff --git a/package-lock.json b/package-lock.json index 122607c..6037a37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "dotenv": "^9.0.2", "emoji-regex": "^9.2.2", "eris": "^0.15.1", - "eris-fleet": "^0.3.7", + "eris-fleet": "github:esmBot/eris-fleet", "file-type": "^16.1.0", "jsqr": "^1.3.1", "lavacord": "^1.1.9", @@ -23,7 +23,8 @@ "node-emoji": "^1.10.0", "node-fetch": "^2.6.1", "qrcode": "^1.4.4", - "sharp": "^0.28.2" + "sharp": "^0.28.2", + "winston": "^3.3.3" }, "devDependencies": { "@babel/eslint-parser": "^7.13.8", @@ -464,6 +465,16 @@ "node": ">=6.9.0" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", @@ -648,6 +659,11 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -979,6 +995,32 @@ "dev": true, "peer": true }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "dependencies": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "node_modules/colorspace/node_modules/color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dependencies": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1158,6 +1200,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -1195,8 +1242,8 @@ }, "node_modules/eris-fleet": { "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eris-fleet/-/eris-fleet-0.3.7.tgz", - "integrity": "sha512-irrGAZIwTXWxIfsSoi8YIm0nHImUADKG+wSr7yk5QgJfSFzIpCEgqFr4x7hdskfcwRa4CCR2HUrjuWDc0zITvg==", + "resolved": "git+ssh://git@github.com/esmBot/eris-fleet.git#7cf997d73f24c3ba3d17df978f0b672adaa021dd", + "license": "MIT", "peerDependencies": { "eris": "^0.15.0" } @@ -1585,6 +1632,16 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "node_modules/fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1649,6 +1706,11 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -1947,6 +2009,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -2028,6 +2098,11 @@ "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==", "optional": true }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/lavacord": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/lavacord/-/lavacord-1.1.9.tgz", @@ -2089,6 +2164,18 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "dependencies": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2314,8 +2401,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nan": { "version": "2.14.2", @@ -2424,6 +2510,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -3157,6 +3251,14 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -3353,6 +3455,11 @@ "node": ">= 6" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3392,6 +3499,11 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3537,6 +3649,50 @@ "node": ">=4" } }, + "node_modules/winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dependencies": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -4039,6 +4195,16 @@ "to-fast-properties": "^2.0.0" } }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", @@ -4192,6 +4358,11 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4445,6 +4616,31 @@ "dev": true, "peer": true }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + }, + "dependencies": { + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4580,6 +4776,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4608,9 +4809,8 @@ } }, "eris-fleet": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eris-fleet/-/eris-fleet-0.3.7.tgz", - "integrity": "sha512-irrGAZIwTXWxIfsSoi8YIm0nHImUADKG+wSr7yk5QgJfSFzIpCEgqFr4x7hdskfcwRa4CCR2HUrjuWDc0zITvg==", + "version": "git+ssh://git@github.com/esmBot/eris-fleet.git#7cf997d73f24c3ba3d17df978f0b672adaa021dd", + "from": "eris-fleet@github:esmBot/eris-fleet", "requires": {} }, "erlpack": { @@ -4899,6 +5099,16 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4948,6 +5158,11 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -5171,6 +5386,11 @@ "is-extglob": "^2.1.1" } }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -5237,6 +5457,11 @@ "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==", "optional": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "lavacord": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/lavacord/-/lavacord-1.1.9.tgz", @@ -5288,6 +5513,18 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5439,8 +5676,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "devOptional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "nan": { "version": "2.14.2", @@ -5534,6 +5770,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -6087,6 +6331,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -6250,6 +6499,11 @@ } } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6276,6 +6530,11 @@ "ieee754": "^1.2.1" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -6387,6 +6646,43 @@ } } }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 64b9baa..3e446d5 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dotenv": "^9.0.2", "emoji-regex": "^9.2.2", "eris": "^0.15.1", - "eris-fleet": "^0.3.7", + "eris-fleet": "github:esmBot/eris-fleet", "file-type": "^16.1.0", "jsqr": "^1.3.1", "lavacord": "^1.1.9", @@ -38,7 +38,8 @@ "node-emoji": "^1.10.0", "node-fetch": "^2.6.1", "qrcode": "^1.4.4", - "sharp": "^0.28.2" + "sharp": "^0.28.2", + "winston": "^3.3.3" }, "devDependencies": { "@babel/eslint-parser": "^7.13.8", From 97050f0cf15cce79be4ca795ae6922f067c5cc33 Mon Sep 17 00:00:00 2001 From: Essem Date: Mon, 5 Jul 2021 19:20:21 -0500 Subject: [PATCH 3/8] Attempt to move image processing to an eris-fleet service --- api/index.js | 1 - app.js | 16 +- classes/imageCommand.js | 5 +- commands/general/imagereload.js | 14 +- commands/general/imagestats.js | 5 +- shard.js | 51 +----- utils/image.js | 230 ------------------------- utils/services/image.js | 286 ++++++++++++++++++++++++++++++++ 8 files changed, 302 insertions(+), 306 deletions(-) create mode 100644 utils/services/image.js diff --git a/api/index.js b/api/index.js index 6d427ea..074b26b 100644 --- a/api/index.js +++ b/api/index.js @@ -1,6 +1,5 @@ require("dotenv").config(); const os = require("os"); -//const { run } = require("../utils/image-runner.js"); const { Worker } = require("worker_threads"); const path = require("path"); const http = require("http"); diff --git a/app.js b/app.js index 75890b5..a885a72 100644 --- a/app.js +++ b/app.js @@ -51,6 +51,9 @@ const Admiral = new Fleet({ name: "Starting esmBot..." } }, + whatToLog: { + blacklist: ["stats_update"] + }, clientOptions: { disableEvents: { CHANNEL_DELETE: true, @@ -82,7 +85,11 @@ const Admiral = new Fleet({ stats: { requestTimeout: 30000 } - } + }, + services: [ + //{ name: "prometheus", path: path.join(__dirname, "./utils/services/prometheus.js") }, + { name: "image", path: path.join(__dirname, "./utils/services/image.js")} + ] }); if (isMaster) { @@ -119,12 +126,9 @@ if (isMaster) { warn: "yellow", error: "red" }); - + Admiral.on("log", (m) => logger.main(m)); - Admiral.on("info", (m) => { - console.log("hi"); - logger.info(m); - }); + Admiral.on("info", (m) => logger.info(m)); Admiral.on("debug", (m) => logger.debug(m)); Admiral.on("warn", (m) => logger.warn(m)); Admiral.on("error", (m) => logger.error(m)); diff --git a/classes/imageCommand.js b/classes/imageCommand.js index 70800f8..8ffff0a 100644 --- a/classes/imageCommand.js +++ b/classes/imageCommand.js @@ -1,5 +1,4 @@ const Command = require("./command.js"); -const magick = require("../utils/image.js"); const imageDetect = require("../utils/imagedetect.js"); const collections = require("../utils/collections.js"); const { emotes } = require("../messages.json"); @@ -99,12 +98,12 @@ class ImageCommand extends Command { } try { - const { buffer, type } = await magick.run(magickParams).catch(e => { + const { buffer, type } = await this.ipc.command("image", { type: "run", obj: magickParams }, true).catch(e => { throw e; }); if (type === "nogif" && this.constructor.requiresGIF) return "That isn't a GIF!"; return { - file: buffer, + file: Buffer.from(buffer.data), name: `${this.constructor.command}.${type}` }; } catch (e) { diff --git a/commands/general/imagereload.js b/commands/general/imagereload.js index 2a4230e..df8f3e1 100644 --- a/commands/general/imagereload.js +++ b/commands/general/imagereload.js @@ -1,21 +1,9 @@ -const image = require("../../utils/image.js"); -const logger = require("../../utils/logger.js"); const Command = require("../../classes/command.js"); class ImageReloadCommand extends Command { async run() { if (this.message.author.id !== process.env.OWNER) return "Only the bot owner can reload the image servers!"; - await image.disconnect(); - await image.repopulate(); - let amount = 0; - for (const server of image.servers) { - try { - await image.connect(server); - amount += 1; - } catch (e) { - logger.error(e); - } - } + const amount = await this.ipc.command("image", { type: "reload" }, true); if (amount > 0) { return `Successfully connected to ${amount} image servers.`; } else { diff --git a/commands/general/imagestats.js b/commands/general/imagestats.js index b416e8a..2236c02 100644 --- a/commands/general/imagestats.js +++ b/commands/general/imagestats.js @@ -1,8 +1,8 @@ -const image = require("../../utils/image.js"); const Command = require("../../classes/command.js"); class ImageStatsCommand extends Command { async run() { + const servers = await this.ipc.command("image", { type: "stats" }, true); const embed = { embed: { "author": { @@ -10,11 +10,10 @@ class ImageStatsCommand extends Command { "icon_url": this.client.user.avatarURL }, "color": 16711680, - "description": `The bot is currently connected to ${image.connections.size} image server(s).`, + "description": `The bot is currently connected to ${servers.length} image server(s).`, "fields": [] } }; - const servers = await image.getRunning(); for (let i = 0; i < servers.length; i++) { embed.embed.fields.push({ name: `Server ${i + 1}`, diff --git a/shard.js b/shard.js index 92ddb8a..bdc6cfd 100644 --- a/shard.js +++ b/shard.js @@ -8,8 +8,6 @@ const logger = require("./utils/logger.js"); const handler = require("./utils/handler.js"); // lavalink stuff const sound = require("./utils/soundplayer.js"); -// image processing stuff -const image = require("./utils/image.js"); // database stuff const database = require("./utils/database.js"); // command collections @@ -21,7 +19,6 @@ const misc = require("./utils/misc.js"); // generate help page const helpGenerator = process.env.OUTPUT !== "" ? require("./utils/help.js") : null; -const http = require("http"); class Shard extends BaseClusterWorker { constructor(bot) { @@ -53,17 +50,6 @@ class Shard extends BaseClusterWorker { this.bot.on(eventName, event.bind(null, this.bot, this.clusterID, this.workerID, this.ipc)); } - // connect to image api if enabled - if (process.env.API === "true") { - for (const server of image.servers) { - try { - await image.connect(server); - } catch (e) { - logger.error(e); - } - } - } - // generate docs if (helpGenerator) { await helpGenerator.generateList(); @@ -73,41 +59,6 @@ class Shard extends BaseClusterWorker { } } - if (process.env.METRICS !== "" && process.env.METRICS !== undefined) { - const httpServer = http.createServer(async (req, res) => { - if (req.method !== "GET") { - res.statusCode = 405; - return res.end("GET only"); - } - res.write(`# HELP connected_workers Number of workers connected -# TYPE connected_workers gauge -connected_workers ${image.connections.size} -# HELP running_jobs Number of running jobs on this worker -# TYPE running_jobs gauge -# HELP queued_jobs Number of queued jobs on this worker -# TYPE queued_jobs gauge -# HELP max_jobs Number of max allowed jobs on this worker -# TYPE max_jobs gauge -# HELP command_count Number of times a command has been run -# TYPE command_count counter -`); - const servers = await image.getRunning(); - for (const [i, w] of servers.entries()) { - res.write(`running_jobs{worker="${i}"} ${w.runningJobs}\n`); - res.write(`queued_jobs{worker="${i}"} ${w.queued}\n`); - res.write(`max_jobs{worker="${i}"} ${w.max}\n`); - } - const counts = await database.getCounts(); - for (const [i, w] of Object.entries(counts)) { - res.write(`command_count{command="${i}"} ${w}\n`); - } - res.end(); - }); - httpServer.listen(process.env.METRICS, () => { - logger.log("info", `Serving metrics at ${process.env.METRICS}`); - }); - } - this.ipc.register("reload", async (message) => { const result = await handler.unload(message.cmd); if (result) return this.ipc.broadcast("reloadFail", { result: result }); @@ -156,7 +107,7 @@ connected_workers ${image.connections.size} } shutdown(done) { - logger.log("warn", "SIGINT detected, shutting down..."); + logger.log("warn", "Shutting down..."); this.bot.editStatus("dnd", { name: "Restarting/shutting down..." }); diff --git a/utils/image.js b/utils/image.js index 7e7afaa..593b11c 100644 --- a/utils/image.js +++ b/utils/image.js @@ -1,12 +1,6 @@ -const magick = require("../build/Release/image.node"); -const { Worker } = require("worker_threads"); const fetch = require("node-fetch"); const fs = require("fs"); -const WebSocket = require("ws"); const fileType = require("file-type"); -const path = require("path"); -const { EventEmitter } = require("events"); -const logger = require("./logger.js"); const formats = ["image/jpeg", "image/png", "image/webp", "image/gif", "video/mp4", "video/webm", "video/mov"]; @@ -16,183 +10,6 @@ exports.connections = new Map(); exports.servers = JSON.parse(fs.readFileSync("./servers.json", { encoding: "utf8" })).image; -const chooseServer = async (ideal) => { - if (ideal.length === 0) throw "No available servers"; - const sorted = ideal.sort((a, b) => { - return b.load - a.load; - }); - return sorted[0]; -}; - -exports.repopulate = async () => { - const data = await fs.promises.readFile("./servers.json", { encoding: "utf8" }); - this.servers = JSON.parse(data).image; - return; -}; - -exports.getRunning = async () => { - let serversLeft = this.connections.size; - const statuses = []; - for (const address of this.connections.keys()) { - const connection = this.connections.get(address); - if (connection.readyState !== 0 && connection.readyState !== 1) { - serversLeft--; - continue; - } - const controller = new AbortController(); // eslint-disable-line no-undef - const timeout = setTimeout(() => { - controller.abort(); - }, 2000); - try { - const statusRequest = await fetch(`http://${address}:8080/running`, { signal: controller.signal }); - clearTimeout(timeout); - const status = await statusRequest.json(); - serversLeft--; - statuses.push(status); - } catch (e) { - if (e.name === "AbortError") { - serversLeft--; - continue; - } else if (e.code === "ECONNREFUSED") { - serversLeft--; - continue; - } - throw e; - } - } - if (!serversLeft) { - return statuses; - } else { - throw new Error("Loop ended before all servers could be checked"); - } -}; - -exports.connect = async (server) => { - const connection = new WebSocket(`ws://${server}:8080/sock`); - connection.on("message", async (msg) => { - const opcode = msg.readUint8(0); - const req = msg.slice(37, msg.length); - const uuid = msg.slice(1, 37).toString(); - if (opcode === 0x00) { // Job queued - if (this.jobs[req]) { - this.jobs[req].event.emit("uuid", uuid); - } - } else if (opcode === 0x01) { // Job completed successfully - // the image API sends all job responses over the same socket; make sure this is ours - if (this.jobs[uuid]) { - const imageReq = await fetch(`http://${server}:8080/image?id=${uuid}`); - const image = await imageReq.buffer(); - // The response data is given as the file extension/ImageMagick type of the image (e.g. "png"), followed - // by a newline, followed by the image data. - - this.jobs[uuid].event.emit("image", image, imageReq.headers.get("ext")); - } - } else if (opcode === 0x02) { // Job errored - if (this.jobs[uuid]) { - this.jobs[uuid].event.emit("error", new Error(req)); - } - } - }); - connection.on("error", (e) => { - logger.error(e.toString()); - }); - connection.once("close", () => { - for (const uuid of Object.keys(this.jobs)) { - if (this.jobs[uuid].addr === server) { - this.jobs[uuid].event.emit("error", "Job ended prematurely due to a closed connection; please run your image job again"); - delete this.jobs[uuid]; - } - } - //logger.log(`Lost connection to ${server}, attempting to reconnect...`); - this.connections.delete(server); - }); - this.connections.set(server, connection); -}; - -exports.disconnect = async () => { - for (const connection of this.connections.values()) { - connection.close(); - } - for (const uuid of Object.keys(this.jobs)) { - this.jobs[uuid].event.emit("error", "Job ended prematurely (not really an error; just run your image job again)"); - delete this.jobs[uuid]; - } - this.connections.clear(); - return; -}; - -const getIdeal = async () => { - let serversLeft = this.connections.size; - if (serversLeft < this.servers.length) { - for (const server of this.servers) { - try { - if (!this.connections.has(server)) await this.connect(server); - } catch (e) { - logger.error(e); - } - } - serversLeft = this.connections.size; - } - const idealServers = []; - for (const address of this.connections.keys()) { - const connection = this.connections.get(address); - if (connection.readyState !== 0 && connection.readyState !== 1) { - serversLeft--; - continue; - } - const controller = new AbortController(); // eslint-disable-line no-undef - const timeout = setTimeout(() => { - controller.abort(); - }, 5000); - try { - const statusRequest = await fetch(`http://${address}:8080/status`, { signal: controller.signal }); - clearTimeout(timeout); - const status = await statusRequest.text(); - serversLeft--; - idealServers.push({ - addr: address, - load: parseInt(status) - }); - } catch (e) { - if (e.name === "AbortError") { - serversLeft--; - continue; - } else if (e.code === "ECONNREFUSED") { - serversLeft--; - continue; - } - throw e; - } finally { - clearTimeout(timeout); - } - } - if (!serversLeft) { - const server = await chooseServer(idealServers); - return { addr: server.addr, sock: this.connections.get(server.addr) }; - } else { - throw new Error("Loop ended before all servers could be checked"); - } -}; - -const start = async (object, num) => { - const currentServer = await getIdeal(); - const data = Buffer.concat([Buffer.from([0x01 /* queue job */]), Buffer.from(num.length.toString()), Buffer.from(num), Buffer.from(JSON.stringify(object))]); - currentServer.sock.send(data); - const event = new EventEmitter(); - this.jobs[num] = { event, addr: currentServer.addr }; - const uuid = await new Promise((resolve, reject) => { - event.once("uuid", (uuid) => resolve(uuid)); - event.once("error", reject); - }); - delete this.jobs[num]; - this.jobs[uuid] = { event: event, addr: currentServer.addr }; - return { uuid: uuid, event: event }; -}; - -exports.check = (cmd) => { - return magick[cmd] ? true : false; -}; - exports.getType = async (image, extraReturnTypes) => { if (!image.startsWith("http")) { const imageType = await fileType.fromFile(image); @@ -234,50 +51,3 @@ exports.getType = async (image, extraReturnTypes) => { } return type; }; - -exports.run = (object) => { - return new Promise((resolve, reject) => { - if (process.env.API === "true") { - // Connect to best image server - const num = Math.floor(Math.random() * 100000).toString().slice(0, 5); - const timeout = setTimeout(() => { - if (this.jobs[num]) delete this.jobs[num]; - reject("the image request timed out after 25 seconds. Try uploading your image elsewhere."); - }, 25000); - start(object, num).catch(err => { // incredibly hacky code incoming - clearTimeout(timeout); - if (err instanceof Error) return reject(err); - return err; - }).then((data) => { - clearTimeout(timeout); - if (!data.event) reject("Not connected to image server"); - data.event.once("image", (image, type) => { - delete this.jobs[data.uuid]; - const payload = { - // Take just the image data - buffer: image, - type: type - }; - resolve(payload); - }); - data.event.once("error", (err) => { - delete this.jobs[data.uuid]; - reject(err); - }); - return; - }).catch(err => reject(err)); - } else { - // Called from command (not using image API) - const worker = new Worker(path.join(__dirname, "image-runner.js"), { - workerData: object - }); - worker.once("message", (data) => { - resolve({ - buffer: Buffer.from([...data.buffer]), - type: data.fileExtension - }); - }); - worker.once("error", reject); - } - }); -}; diff --git a/utils/services/image.js b/utils/services/image.js new file mode 100644 index 0000000..681bafc --- /dev/null +++ b/utils/services/image.js @@ -0,0 +1,286 @@ +const { BaseServiceWorker } = require("eris-fleet"); +const logger = require("../logger.js"); +const fetch = require("node-fetch"); +const WebSocket = require("ws"); +const fs = require("fs"); +const path = require("path"); +const { Worker } = require("worker_threads"); +const { EventEmitter } = require("events"); + +class ImageWorker extends BaseServiceWorker { + constructor(setup) { + super(setup); + + if (process.env.API === "true") { + this.jobs = {}; + this.connections = new Map(); + this.servers = JSON.parse(fs.readFileSync("./servers.json", { encoding: "utf8" })).image; + } + + this.begin().then(() => this.serviceReady()); + } + + async begin() { + // connect to image api if enabled + if (process.env.API === "true") { + for (const server of this.servers) { + try { + await this.connect(server); + } catch (e) { + logger.error(e); + } + } + } + } + + async repopulate() { + const data = await fs.promises.readFile("./servers.json", { encoding: "utf8" }); + this.servers = JSON.parse(data).image; + return; + } + + async getRunning() { + let serversLeft = this.connections.size; + const statuses = []; + for (const address of this.connections.keys()) { + const connection = this.connections.get(address); + if (connection.readyState !== 0 && connection.readyState !== 1) { + serversLeft--; + continue; + } + const controller = new AbortController(); // eslint-disable-line no-undef + const timeout = setTimeout(() => { + controller.abort(); + }, 2000); + try { + const statusRequest = await fetch(`http://${address}:8080/running`, { signal: controller.signal }); + clearTimeout(timeout); + const status = await statusRequest.json(); + serversLeft--; + statuses.push(status); + } catch (e) { + if (e.name === "AbortError") { + serversLeft--; + continue; + } else if (e.code === "ECONNREFUSED") { + serversLeft--; + continue; + } + throw e; + } + } + if (!serversLeft) { + return statuses; + } else { + throw new Error("Loop ended before all servers could be checked"); + } + } + + async chooseServer(ideal) { + if (ideal.length === 0) throw "No available servers"; + const sorted = ideal.sort((a, b) => { + return b.load - a.load; + }); + return sorted[0]; + } + + async getIdeal() { + let serversLeft = this.connections.size; + if (serversLeft < this.servers.length) { + for (const server of this.servers) { + try { + if (!this.connections.has(server)) await this.connect(server); + } catch (e) { + logger.error(e); + } + } + serversLeft = this.connections.size; + } + const idealServers = []; + for (const address of this.connections.keys()) { + const connection = this.connections.get(address); + if (connection.readyState !== 0 && connection.readyState !== 1) { + serversLeft--; + continue; + } + const controller = new AbortController(); // eslint-disable-line no-undef + const timeout = setTimeout(() => { + controller.abort(); + }, 5000); + try { + const statusRequest = await fetch(`http://${address}:8080/status`, { signal: controller.signal }); + clearTimeout(timeout); + const status = await statusRequest.text(); + serversLeft--; + idealServers.push({ + addr: address, + load: parseInt(status) + }); + } catch (e) { + if (e.name === "AbortError") { + serversLeft--; + continue; + } else if (e.code === "ECONNREFUSED") { + serversLeft--; + continue; + } + throw e; + } finally { + clearTimeout(timeout); + } + } + if (!serversLeft) { + const server = await this.chooseServer(idealServers); + return { addr: server.addr, sock: this.connections.get(server.addr) }; + } else { + throw new Error("Loop ended before all servers could be checked"); + } + } + + async connect(server) { + const connection = new WebSocket(`ws://${server}:8080/sock`); + connection.on("message", async (msg) => { + const opcode = msg.readUint8(0); + const req = msg.slice(37, msg.length); + const uuid = msg.slice(1, 37).toString(); + if (opcode === 0x00) { // Job queued + if (this.jobs[req]) { + this.jobs[req].event.emit("uuid", uuid); + } + } else if (opcode === 0x01) { // Job completed successfully + // the image API sends all job responses over the same socket; make sure this is ours + if (this.jobs[uuid]) { + const imageReq = await fetch(`http://${server}:8080/image?id=${uuid}`); + const image = await imageReq.buffer(); + // The response data is given as the file extension/ImageMagick type of the image (e.g. "png"), followed + // by a newline, followed by the image data. + + this.jobs[uuid].event.emit("image", image, imageReq.headers.get("ext")); + } + } else if (opcode === 0x02) { // Job errored + if (this.jobs[uuid]) { + this.jobs[uuid].event.emit("error", new Error(req)); + } + } + }); + connection.on("error", (e) => { + logger.error(e.toString()); + }); + connection.once("close", () => { + for (const uuid of Object.keys(this.jobs)) { + if (this.jobs[uuid].addr === server) { + this.jobs[uuid].event.emit("error", "Job ended prematurely due to a closed connection; please run your image job again"); + delete this.jobs[uuid]; + } + } + //logger.log(`Lost connection to ${server}, attempting to reconnect...`); + this.connections.delete(server); + }); + this.connections.set(server, connection); + } + + async disconnect() { + for (const connection of this.connections.values()) { + connection.close(); + } + for (const uuid of Object.keys(this.jobs)) { + this.jobs[uuid].event.emit("error", "Job ended prematurely (not really an error; just run your image job again)"); + delete this.jobs[uuid]; + } + this.connections.clear(); + return; + } + + async start(object, num) { + const currentServer = await this.getIdeal(); + const data = Buffer.concat([Buffer.from([0x01 /* queue job */]), Buffer.from(num.length.toString()), Buffer.from(num), Buffer.from(JSON.stringify(object))]); + currentServer.sock.send(data); + const event = new EventEmitter(); + this.jobs[num] = { event, addr: currentServer.addr }; + const uuid = await new Promise((resolve, reject) => { + event.once("uuid", (uuid) => resolve(uuid)); + event.once("error", reject); + }); + delete this.jobs[num]; + this.jobs[uuid] = { event: event, addr: currentServer.addr }; + return { uuid: uuid, event: event }; + } + + run(object) { + return new Promise((resolve, reject) => { + if (process.env.API === "true") { + // Connect to best image server + const num = Math.floor(Math.random() * 100000).toString().slice(0, 5); + const timeout = setTimeout(() => { + if (this.jobs[num]) delete this.jobs[num]; + reject("the image request timed out after 25 seconds. Try uploading your image elsewhere."); + }, 25000); + this.start(object, num).catch(err => { // incredibly hacky code incoming + clearTimeout(timeout); + if (err instanceof Error) return reject(err); + return err; + }).then((data) => { + clearTimeout(timeout); + if (!data.event) reject("Not connected to image server"); + data.event.once("image", (image, type) => { + delete this.jobs[data.uuid]; + const payload = { + // Take just the image data + buffer: image, + type: type + }; + resolve(payload); + }); + data.event.once("error", (err) => { + delete this.jobs[data.uuid]; + reject(err); + }); + return; + }).catch(err => reject(err)); + } else { + // Called from command (not using image API) + const worker = new Worker(path.join(__dirname, "../image-runner.js"), { + workerData: object + }); + worker.once("message", (data) => { + resolve({ + buffer: Buffer.from([...data.buffer]), + type: data.fileExtension + }); + }); + worker.once("error", reject); + } + }); + } + + async handleCommand(data) { + try { + if (data.type === "run") { + return await this.run(data.obj); + } else if (data.type === "reload") { + await this.disconnect(); + await this.repopulate(); + let amount = 0; + for (const server of this.servers) { + try { + await this.connect(server); + amount += 1; + } catch (e) { + logger.error(e); + } + } + return amount; + } else if (data.type === "stats") { + return await this.getRunning(); + } + } catch (err) { + return { err: err.message }; + } + } + + shutdown(done) { + done(); + } +} + +module.exports = ImageWorker; From a91720c598a56e5fa793b059f70d41f9297f34d4 Mon Sep 17 00:00:00 2001 From: Essem Date: Tue, 6 Jul 2021 07:53:09 -0500 Subject: [PATCH 4/8] Some fixes --- classes/musicCommand.js | 2 +- commands/general/reload.js | 2 +- commands/general/soundreload.js | 2 +- shard.js | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/classes/musicCommand.js b/classes/musicCommand.js index 98ec336..a7a1a04 100644 --- a/classes/musicCommand.js +++ b/classes/musicCommand.js @@ -3,7 +3,7 @@ const soundPlayer = require("../utils/soundplayer.js"); class MusicCommand extends Command { constructor(client, cluster, worker, ipc, message, args, content, specialArgs) { - super(client, cluster, ipc, message, args, content, specialArgs); + super(client, cluster, worker, ipc, message, args, content, specialArgs); this.connection = soundPlayer.players.get(message.channel.guild.id); } diff --git a/commands/general/reload.js b/commands/general/reload.js index e96ed6c..9276243 100644 --- a/commands/general/reload.js +++ b/commands/general/reload.js @@ -6,7 +6,7 @@ class ReloadCommand extends Command { return new Promise((resolve) => { if (this.message.author.id !== process.env.OWNER) resolve("Only the bot owner can reload commands!"); if (this.args.length === 0) resolve("You need to provide a command to reload!"); - this.ipc.broadcast("reload", { cmd: this.args[0] }); + this.ipc.broadcast("reload", this.args[0]); this.ipc.register("reloadSuccess", () => { this.ipc.unregister("reloadSuccess"); this.ipc.unregister("reloadFail"); diff --git a/commands/general/soundreload.js b/commands/general/soundreload.js index 8d6a766..e349ccb 100644 --- a/commands/general/soundreload.js +++ b/commands/general/soundreload.js @@ -10,7 +10,7 @@ class SoundReloadCommand extends Command { this.ipc.register("soundReloadSuccess", (msg) => { this.ipc.unregister("soundReloadSuccess"); this.ipc.unregister("soundReloadFail"); - resolve(`Successfully connected to ${msg.length} Lavalink node(s).`); + resolve(`Successfully connected to ${msg.msg.length} Lavalink node(s).`); }); this.ipc.register("soundReloadFail", () => { this.ipc.unregister("soundReloadSuccess"); diff --git a/shard.js b/shard.js index bdc6cfd..60dc6b3 100644 --- a/shard.js +++ b/shard.js @@ -60,9 +60,9 @@ class Shard extends BaseClusterWorker { } this.ipc.register("reload", async (message) => { - const result = await handler.unload(message.cmd); + const result = await handler.unload(message.msg); if (result) return this.ipc.broadcast("reloadFail", { result: result }); - const result2 = await handler.load(collections.paths.get(message.cmd)); + const result2 = await handler.load(collections.paths.get(message.msg)); if (result2) return this.ipc.broadcast("reloadFail", { result: result2 }); return this.ipc.broadcast("reloadSuccess"); }); From 11a77df700d235d734e717bb14d2cd9fb783c61d Mon Sep 17 00:00:00 2001 From: Essem Date: Tue, 6 Jul 2021 08:25:12 -0500 Subject: [PATCH 5/8] maybe this fixes the audio message deleting? --- utils/soundplayer.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/utils/soundplayer.js b/utils/soundplayer.js index 002c368..eb0019b 100644 --- a/utils/soundplayer.js +++ b/utils/soundplayer.js @@ -90,11 +90,15 @@ exports.play = async (client, sound, message, music = false) => { } }; -exports.nextSong = async (client, message, connection, track, info, music, voiceChannel, loop = false, inQueue = false, lastTrack = null, oldPlaying = null) => { +exports.nextSong = async (client, message, connection, track, info, music, voiceChannel, loop = false, inQueue = false, lastTrack = null) => { const parts = Math.floor((0 / info.length) * 10); let playingMessage; + if (!music && this.players.get(voiceChannel.guild.id)) { + const playMessage = this.players.get(voiceChannel.guild.id).playMessage; + if (playMessage.channel.messages.get(playMessage.id)) playMessage.delete(); + } if (lastTrack === track) { - playingMessage = oldPlaying; + playingMessage = this.players.get(voiceChannel.guild.id).playMessage; } else { playingMessage = await client.createMessage(message.channel.id, !music ? "🔊 Playing sound..." : { "embed": { @@ -123,10 +127,12 @@ exports.nextSong = async (client, message, connection, track, info, music, voice }); } await connection.play(track); - this.players.set(voiceChannel.guild.id, { player: connection, type: music ? "music" : "sound", host: message.author.id, voiceChannel: voiceChannel, originalChannel: message.channel, loop: loop }); + this.players.set(voiceChannel.guild.id, { player: connection, type: music ? "music" : "sound", host: message.author.id, voiceChannel: voiceChannel, originalChannel: message.channel, loop: loop, playMessage: playingMessage }); if (inQueue && connection.listeners("error").length === 0) { connection.on("error", (error) => { if (playingMessage.channel.messages.get(playingMessage.id)) playingMessage.delete(); + const playMessage = this.players.get(voiceChannel.guild.id).playMessage; + if (playMessage.channel.messages.get(playMessage.id)) playMessage.delete(); this.manager.leave(voiceChannel.guild.id); connection.destroy(); this.players.delete(voiceChannel.guild.id); @@ -136,11 +142,11 @@ exports.nextSong = async (client, message, connection, track, info, music, voice } if (connection.listeners("end").length === 0) { connection.on("end", async (data) => { + const player = this.players.get(voiceChannel.guild.id); if (data.reason === "REPLACED") return; const queue = this.queues.get(voiceChannel.guild.id); - const isLooping = this.players.get(voiceChannel.guild.id).loop; let newQueue; - if (isLooping) { + if (player.loop) { queue.push(queue.shift()); newQueue = queue; } else { @@ -154,10 +160,12 @@ exports.nextSong = async (client, message, connection, track, info, music, voice this.queues.delete(voiceChannel.guild.id); if (music) await client.createMessage(message.channel.id, "🔊 The current voice channel session has ended."); if (playingMessage.channel.messages.get(playingMessage.id)) await playingMessage.delete(); + if (player.playMessage.channel.messages.get(player.playMessage.id)) await player.playMessage.delete(); } else { const newTrack = await fetch(`http://${connection.node.host}:${connection.node.port}/decodetrack?track=${encodeURIComponent(newQueue[0])}`, { headers: { Authorization: connection.node.password } }).then(res => res.json()); - this.nextSong(client, message, connection, newQueue[0], newTrack, music, voiceChannel, isLooping, true, track, playingMessage); + this.nextSong(client, message, connection, newQueue[0], newTrack, music, voiceChannel, player.loop, true, track); if (newQueue[0] !== track && playingMessage.channel.messages.get(playingMessage.id)) await playingMessage.delete(); + if (newQueue[0] !== track && player.playMessage.channel.messages.get(player.playMessage.id)) await player.playMessage.delete(); } }); } From 75801687a436600b43946d4cf240be5566088fd6 Mon Sep 17 00:00:00 2001 From: Essem Date: Tue, 6 Jul 2021 09:22:51 -0500 Subject: [PATCH 6/8] Re-add Prometheus metrics --- app.js | 2 +- utils/services/prometheus.js | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 utils/services/prometheus.js diff --git a/app.js b/app.js index a885a72..68eb196 100644 --- a/app.js +++ b/app.js @@ -87,7 +87,7 @@ const Admiral = new Fleet({ } }, services: [ - //{ name: "prometheus", path: path.join(__dirname, "./utils/services/prometheus.js") }, + { name: "prometheus", path: path.join(__dirname, "./utils/services/prometheus.js") }, { name: "image", path: path.join(__dirname, "./utils/services/image.js")} ] }); diff --git a/utils/services/prometheus.js b/utils/services/prometheus.js new file mode 100644 index 0000000..ba4a473 --- /dev/null +++ b/utils/services/prometheus.js @@ -0,0 +1,57 @@ +const { BaseServiceWorker } = require("eris-fleet"); +const http = require("http"); +const logger = require("../logger.js"); +const database = require("../database.js"); + +class PrometheusWorker extends BaseServiceWorker { + constructor(setup) { + super(setup); + + if (process.env.METRICS !== "" && process.env.METRICS !== undefined) { + this.httpServer = http.createServer(async (req, res) => { + if (req.method !== "GET") { + res.statusCode = 405; + return res.end("GET only"); + } + res.write(`# HELP command_count Number of times a command has been run +# TYPE command_count counter +`); + if (process.env.API === "true") { + const servers = await this.ipc.command("image", { type: "stats" }, true); + res.write(`# HELP connected_workers Number of workers connected +# TYPE connected_workers gauge +connected_workers ${servers.length} +# HELP running_jobs Number of running jobs on this worker +# TYPE running_jobs gauge +# HELP queued_jobs Number of queued jobs on this worker +# TYPE queued_jobs gauge +# HELP max_jobs Number of max allowed jobs on this worker +# TYPE max_jobs gauge +`); + for (const [i, w] of servers.entries()) { + res.write(`running_jobs{worker="${i}"} ${w.runningJobs}\n`); + res.write(`queued_jobs{worker="${i}"} ${w.queued}\n`); + res.write(`max_jobs{worker="${i}"} ${w.max}\n`); + } + } + const counts = await database.getCounts(); + for (const [i, w] of Object.entries(counts)) { + res.write(`command_count{command="${i}"} ${w}\n`); + } + res.end(); + }); + this.httpServer.listen(process.env.METRICS, () => { + logger.log("info", `Serving metrics at ${process.env.METRICS}`); + }); + } + + this.serviceReady(); + } + + shutdown(done) { + this.httpServer.close(); + done(); + } +} + +module.exports = PrometheusWorker; From 0483e6801643a1081cae0868a0b47628879bc56a Mon Sep 17 00:00:00 2001 From: Essem Date: Tue, 6 Jul 2021 09:23:27 -0500 Subject: [PATCH 7/8] Sound playback is pain --- utils/soundplayer.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/utils/soundplayer.js b/utils/soundplayer.js index eb0019b..5cbe9d9 100644 --- a/utils/soundplayer.js +++ b/utils/soundplayer.js @@ -142,9 +142,9 @@ exports.nextSong = async (client, message, connection, track, info, music, voice } if (connection.listeners("end").length === 0) { connection.on("end", async (data) => { - const player = this.players.get(voiceChannel.guild.id); if (data.reason === "REPLACED") return; const queue = this.queues.get(voiceChannel.guild.id); + const player = this.players.get(voiceChannel.guild.id); let newQueue; if (player.loop) { queue.push(queue.shift()); @@ -159,13 +159,21 @@ exports.nextSong = async (client, message, connection, track, info, music, voice this.players.delete(voiceChannel.guild.id); this.queues.delete(voiceChannel.guild.id); if (music) await client.createMessage(message.channel.id, "🔊 The current voice channel session has ended."); - if (playingMessage.channel.messages.get(playingMessage.id)) await playingMessage.delete(); - if (player.playMessage.channel.messages.get(player.playMessage.id)) await player.playMessage.delete(); + try { + if (playingMessage.channel.messages.get(playingMessage.id)) await playingMessage.delete(); + if (player.playMessage.channel.messages.get(player.playMessage.id)) await player.playMessage.delete(); + } catch { + // no-op + } } else { const newTrack = await fetch(`http://${connection.node.host}:${connection.node.port}/decodetrack?track=${encodeURIComponent(newQueue[0])}`, { headers: { Authorization: connection.node.password } }).then(res => res.json()); this.nextSong(client, message, connection, newQueue[0], newTrack, music, voiceChannel, player.loop, true, track); - if (newQueue[0] !== track && playingMessage.channel.messages.get(playingMessage.id)) await playingMessage.delete(); - if (newQueue[0] !== track && player.playMessage.channel.messages.get(player.playMessage.id)) await player.playMessage.delete(); + try { + if (newQueue[0] !== track && playingMessage.channel.messages.get(playingMessage.id)) await playingMessage.delete(); + if (newQueue[0] !== track && player.playMessage.channel.messages.get(player.playMessage.id)) await player.playMessage.delete(); + } catch { + // no-op + } } }); } From bc2826ccbb638a76040fe52541fb3272d208f08a Mon Sep 17 00:00:00 2001 From: Essem Date: Thu, 8 Jul 2021 21:03:19 -0500 Subject: [PATCH 8/8] Removed quote detection from normal arguments --- events/voiceChannelLeave.js | 1 + utils/parseCommand.js | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/events/voiceChannelLeave.js b/events/voiceChannelLeave.js index df8b365..6227f81 100644 --- a/events/voiceChannelLeave.js +++ b/events/voiceChannelLeave.js @@ -3,6 +3,7 @@ const AwaitRejoin = require("../utils/awaitrejoin.js"); const { random } = require("../utils/misc.js"); module.exports = async (client, cluster, worker, ipc, member, oldChannel) => { + if (!oldChannel) return; const connection = soundPlayer.players.get(oldChannel.guild.id); if (connection && connection.type === "music" && oldChannel.id === connection.voiceChannel.id) { if (oldChannel.voiceMembers.filter((i) => i.id !== client.user.id).length === 0) { diff --git a/utils/parseCommand.js b/utils/parseCommand.js index e26cf1e..c37ddea 100644 --- a/utils/parseCommand.js +++ b/utils/parseCommand.js @@ -39,16 +39,6 @@ module.exports = (input) => { } else { args[curr] += `${a} `; } - } else if (a.startsWith("\"")) { - if (a.endsWith("\"")) { - args.push(a.slice(1).slice(0, -1)); - } else { - concated += `${a.slice(1)} `; - } - } else if (a.endsWith("\"")) { - concated += a.slice(0, -1); - args._.push(concated); - concated = ""; } else { if (concated !== "") { concated += `${a} `;