From 9ef265a2969261cda93bf9a71fc79b9f84f92fda Mon Sep 17 00:00:00 2001 From: nolan Date: Tue, 17 Aug 2021 00:15:20 -0700 Subject: [PATCH] still so many changes needed dont fuck with anything --- options.json | 6 ++ src/constants/Commands.json | 7 +++ src/constants/index.js | 1 + src/middleware/BaseClient.js | 8 +++ src/middleware/rest/SlashCommandManager.js | 53 +++++++++++++++- src/structure/DiscordClient.js | 9 ++- src/structure/client/Dispatcher.js | 2 +- src/structure/client/Intercom.js | 35 +++++++++++ src/structure/client/Logger.js | 2 +- src/structure/client/Resolver.js | 2 +- src/structure/client/index.js | 1 + .../commands/moderation/MuteCommand.js | 5 +- .../components/observers/CommandHandler.js | 63 ++----------------- src/structure/interfaces/Argument.js | 5 -- src/structure/interfaces/Command.js | 26 ++------ src/structure/interfaces/Component.js | 4 +- src/structure/interfaces/LegacyCommand.js | 0 src/structure/interfaces/Module.js | 2 +- src/structure/interfaces/Observer.js | 2 +- src/structure/interfaces/SlashCommand.js | 40 ++++++++++++ src/structure/interfaces/index.js | 1 + 21 files changed, 181 insertions(+), 93 deletions(-) create mode 100644 src/constants/Commands.json create mode 100644 src/structure/client/Intercom.js create mode 100644 src/structure/interfaces/LegacyCommand.js create mode 100644 src/structure/interfaces/SlashCommand.js diff --git a/options.json b/options.json index 4138048..dc254ab 100644 --- a/options.json +++ b/options.json @@ -2,11 +2,17 @@ "discord": { "prefix": "]", "developer": "132620781791346688", + "clientId": "697791541690892369", "clientOptions": { }, "shardOptions": { "totalShards": "auto" + }, + "slashCommands": { + "developerGuilds": [ + "264527028751958016" + ] } }, "logger": { diff --git a/src/constants/Commands.json b/src/constants/Commands.json new file mode 100644 index 0000000..f14a4b2 --- /dev/null +++ b/src/constants/Commands.json @@ -0,0 +1,7 @@ +{ + "ApplicationCommandTypes": { + "CHAT_INPUT": 1, + "USER": 2, + "MESSAGE": 3 + } +} \ No newline at end of file diff --git a/src/constants/index.js b/src/constants/index.js index 394f42e..99a8f8b 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -1,3 +1,4 @@ module.exports = { + Commands: require('./Commands.json'), Emojis: require('./Emojis.json') }; \ No newline at end of file diff --git a/src/middleware/BaseClient.js b/src/middleware/BaseClient.js index 3aa9b19..3139d64 100644 --- a/src/middleware/BaseClient.js +++ b/src/middleware/BaseClient.js @@ -28,10 +28,18 @@ class BaseClient extends EventEmitter { await this.shardingManager.spawn(); + await this.slashCommandManager.global([ + { + name: 'ping', + description: "a required description" + } + ]); + } _handleMessage(shard, message) { if(message._logger) return this.logger._handleMessage(shard, message); + if(message._commands) return this.slashCommandManager._handleMessage(message); } } diff --git a/src/middleware/rest/SlashCommandManager.js b/src/middleware/rest/SlashCommandManager.js index bbd7273..891354a 100644 --- a/src/middleware/rest/SlashCommandManager.js +++ b/src/middleware/rest/SlashCommandManager.js @@ -1,5 +1,5 @@ const { REST } = require('@discordjs/rest'); -// const { Routes } = require('discord-api-types/v9'); +const { Routes } = require('discord-api-types/v9'); class SlashCommandManager { @@ -12,6 +12,57 @@ class SlashCommandManager { } + async _handleMessage(message) { + if(message.type === 'global') { + await this.global(message.commands); + } else if(message.type === 'guild') { + await this.guild(message.commands, { guilds: message.guilds }); + } + } + + async guild(commands, { guilds = [] }) { + if(!guilds.length) guilds = this.client._options.discord.slashCommands.developerGuilds; + + const promises = []; + for(const guild of guilds) { + promises.push(this.rest.put( + Routes.applicationGuildCommands(this.client._options.discord.clientId, guild), + { body: commands } + )); + } + + let result = null; + try { + result = await Promise.all(promises); + } catch(error) { + this.client.logger.write('error', `An issue has occured while updating guild commands. Guild command refresh aborted.\n${error.stack || error}`); + } + + if(!result) return null; + + this.client.logger.write('debug', `Refreshed guild slash commands for guild${guilds.length === 1 ? '' : 's'}: ${guilds.join(' ')}`); + return result; + + } + + async global(commands) { + + // try { + // this.client.logger.write('debug', 'Starting global refresh for slash commands.'); + + // await this.rest.put( + // Routes.applicationGuildCommands(this.client._options.discord.clientId, "264527028751958016"), + // { body: [] } + // ); + + // this.client.logger.write('debug', 'Finished global refresh for slash commands.'); + // } catch(error) { + // this.client.logger.write('error', 'Failed to refresh slash commands globally.'); + // this.client.logger.write('error', error?.stack); + // } + + } + } module.exports = SlashCommandManager; \ No newline at end of file diff --git a/src/structure/DiscordClient.js b/src/structure/DiscordClient.js index a6e209e..be110f1 100644 --- a/src/structure/DiscordClient.js +++ b/src/structure/DiscordClient.js @@ -1,6 +1,6 @@ const { Client, Intents } = require('discord.js'); -const { Logger, EventHooker, Registry, Dispatcher, Resolver } = require('./client/'); +const { Logger, Intercom, EventHooker, Registry, Dispatcher, Resolver } = require('./client/'); const { Observer, Command } = require('./interfaces/'); const options = require('../../options.json'); @@ -16,6 +16,7 @@ class DiscordClient extends Client { }); this.eventHooker = new EventHooker(this); + this.intercom = new Intercom(this); this.logger = new Logger(this); this.registry = new Registry(this); @@ -44,11 +45,17 @@ class DiscordClient extends Client { await super.login(process.env.DISCORD_TOKEN); + this.emit('built'); this._built = true; return this; } + get singleton() { + return Boolean(this.shard.ids[0] === 0); + } + + } module.exports = DiscordClient; diff --git a/src/structure/client/Dispatcher.js b/src/structure/client/Dispatcher.js index e9bec9b..8fef550 100644 --- a/src/structure/client/Dispatcher.js +++ b/src/structure/client/Dispatcher.js @@ -26,7 +26,7 @@ class Dispatcher { async dispatch() { const observers = this.client.registry.components - .filter((c) => c.type === 'observer' && !c.disabled) + .filter((c) => c._type === 'observer' && !c.disabled) .sort((a, b) => a.priority - b.priority); this.client.logger.debug(`Starting dispatch on ${observers.size} observers.`); diff --git a/src/structure/client/Intercom.js b/src/structure/client/Intercom.js new file mode 100644 index 0000000..9836abb --- /dev/null +++ b/src/structure/client/Intercom.js @@ -0,0 +1,35 @@ +class Intercom { + + constructor(client) { + + this.client = client; + + if(client.singleton) { + this.client.eventHooker.hook('built', () => { + this._transportCommands(); + }); + } + + } + + send(type, message = {}) { + if(typeof message !== 'object') return false; + return process.send({ + [`_${type}`]: true, + ...message + }); + } + + _transportCommands() { + + const commands = this.client.registry.components + .filter((c) => c._type === 'command' && c.slash) + .map((c) => c.json); + + this.send('commands', { type: 'guild', commands }); + + } + +} + +module.exports = Intercom; \ No newline at end of file diff --git a/src/structure/client/Logger.js b/src/structure/client/Logger.js index a02595b..f503bb9 100644 --- a/src/structure/client/Logger.js +++ b/src/structure/client/Logger.js @@ -56,7 +56,7 @@ class Logger { } async transport(message = 'N/A', opts = {}) { - process.send({ _logger: true, message, ...opts }); + return this.client.intercom.send('logger', { message, ...opts }); } /* Quick & Dirty Functions */ diff --git a/src/structure/client/Resolver.js b/src/structure/client/Resolver.js index ebfe3dc..d600c3b 100644 --- a/src/structure/client/Resolver.js +++ b/src/structure/client/Resolver.js @@ -11,7 +11,7 @@ class Resolver { const string = str.toLowerCase(); const components = this.client.registry.components - .filter((c) => type === 'any' ? ['command', 'setting'].includes(c.type) : c.type === type) + .filter((c) => type === 'any' ? ['command', 'setting'].includes(c._type) : c._type === type) .filter(exact ? filterExact(string) : filterInexact(string)); //eslint-disable-line no-use-before-define return components.size > 0 ? components.values() : []; diff --git a/src/structure/client/index.js b/src/structure/client/index.js index 8c8bc8e..7c327c8 100644 --- a/src/structure/client/index.js +++ b/src/structure/client/index.js @@ -1,5 +1,6 @@ module.exports = { EventHooker: require('./EventHooker.js'), + Intercom: require('./Intercom.js'), Logger: require('./Logger.js'), Dispatcher: require('./Dispatcher.js'), Registry: require('./Registry.js'), diff --git a/src/structure/components/commands/moderation/MuteCommand.js b/src/structure/components/commands/moderation/MuteCommand.js index 9919bb6..6b5dbf9 100644 --- a/src/structure/components/commands/moderation/MuteCommand.js +++ b/src/structure/components/commands/moderation/MuteCommand.js @@ -1,10 +1,11 @@ -const { Command } = require('../../../interfaces/'); +const { SlashCommand } = require('../../../interfaces/'); -class MuteCommand extends Command { +class MuteCommand extends SlashCommand { constructor(client) { super(client, { name: 'mute', + description: "Silence people.", module: 'moderation', arguments: [ ] diff --git a/src/structure/components/observers/CommandHandler.js b/src/structure/components/observers/CommandHandler.js index 16b7922..b43e659 100644 --- a/src/structure/components/observers/CommandHandler.js +++ b/src/structure/components/observers/CommandHandler.js @@ -42,12 +42,14 @@ class CommandHandler extends Observer { async interactionCreate(interaction) { if(!interaction.isCommand()) return undefined; - if(!this.client._built - || message.guild && !message.guild.available) return undefined; + // if(!this.client._built + // || message.guild && !message.guild.available) return undefined; const command = this._matchCommand(interaction.commandName); - if(!command) return await interaction.reply('Command is not synced with client instance.'); + console.log(interaction.commandName) + if(!command) return interaction.reply('Command is not synced with client instance.'); + interaction.reply(command.resolveable); } @@ -76,7 +78,7 @@ class CommandHandler extends Observer { } - _matchCommand(message, commandName) { + _matchCommand(commandName) { const [ command ] = this.client.resolver.components(commandName, 'command', true); if(!command) return null; @@ -85,59 +87,6 @@ class CommandHandler extends Observer { } - async _parseArguments(message, command, parameters) { - - // const arguments = this._combineArguments(command); - - let word = null, - inQuotes = false; - for(const char of parameters.split('')) { - - - - } - - - - } - - _combineArguments(command) { - - if(command._combinedArguments) return command._combinedArguments; - command._combinedArguments = { - shortFlags: {}, - longFlags: {}, - verbals: {} - } - - const combined = command._combinedArguments; - for(const argument of command.arguments) { - if(argument.types.includes('FLAG')) { - //Handle one-argument flags. - let shortFlag = argument.key.slice(1); - const shortValues = Object.values(combined.shortFlags); - if(shortValues.includes(shortFlag)) { - shortFlag = shortFlag.toUpperCase(); - if(shortValues.includes(shortFlag)) { - this.client.logger.warn(`Command "${command.resolveable}" has more than two arguments starting with the letter "${shortFlag}". Argument "${argument.key}" shortflag is being skipped.`) - continue; - } - } - combined.shortFlags[shortFlag] = argument.key; - //Handle multi-argument flags. - combined.longFlags[argument.key] = argument.key; - for(const alias of argument.aliases) combined.longFlags[alias] = argument.key; - } - if(argument.types.includes('VERBAL')) { - combined.verbals[argument.key] = argument.key; - for(const alias of argument.aliases) combined.verbals[alias] = argument.key; - } - } - - return combined; - - } - } module.exports = CommandHandler; \ No newline at end of file diff --git a/src/structure/interfaces/Argument.js b/src/structure/interfaces/Argument.js index fa5db9a..5bdfc56 100644 --- a/src/structure/interfaces/Argument.js +++ b/src/structure/interfaces/Argument.js @@ -1,9 +1,4 @@ const Constants = { - ArgumentTypes: [ - "FLAG", - "VERBAL", - "SLASH" - ], ArgumentOptionTypes: { //https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type "SUB_COMMAND": 1, "SUB_COMMAND_GROUP": 2, diff --git a/src/structure/interfaces/Command.js b/src/structure/interfaces/Command.js index 74915c4..0a3a198 100644 --- a/src/structure/interfaces/Command.js +++ b/src/structure/interfaces/Command.js @@ -7,7 +7,7 @@ class Command extends Component { super(client, { id: options.name, - type: 'command', + _type: 'command', disabled: options.disabled, guarded: options.guarded }); @@ -16,31 +16,17 @@ class Command extends Component { this.name = options.name; this.module = options.module; - this.aliases = options.aliases || []; - - this.description = ""; //Localization Entry - this.usage = options.usage || null; - this.examples = options.examples || []; + this.description = options.description || ""; this.tags = options.tags || []; - this.slash = Boolean(options.slash); - this.restricted = Boolean(options.restricted); - this.showUsage = Boolean(options.showUsage); - this.guildOnly = Boolean(options.guildOnly); + this.restricted = Boolean(options?.restricted); + // this.showUsage = Boolean(options.showUsage); + this.guildOnly = Boolean(options?.guildOnly); this.archivable = options.archivable === undefined ? true : Boolean(options.archivable); - this.arguments = options.arguments || []; + this.slash = Boolean(options?.slash); - this.clientPermissions = options.clientPermissions || []; - this.memberPermissions = options.memberPermissions || []; - - this.throttling = options.throttling || { - usages: 5, - duration: 10 - }; - - this._throttles = new Map(); this._invokes = { success: 0, fail: 0 diff --git a/src/structure/interfaces/Component.js b/src/structure/interfaces/Component.js index 8bb3cd3..5e5ec41 100644 --- a/src/structure/interfaces/Component.js +++ b/src/structure/interfaces/Component.js @@ -4,7 +4,7 @@ class Component { if(!options) return null; this.id = options.id; //Name of the component - this.type = options.type; //Type of component (command, observer, etc.) + this._type = options._type; //Type of component (command, observer, etc.) this.module = options.module || null; //Group/module the component belongs to. @@ -77,7 +77,7 @@ class Component { get resolveable() { - return `${this.type}:${this.id}`; + return `${this._type}:${this.id}`; } } diff --git a/src/structure/interfaces/LegacyCommand.js b/src/structure/interfaces/LegacyCommand.js new file mode 100644 index 0000000..e69de29 diff --git a/src/structure/interfaces/Module.js b/src/structure/interfaces/Module.js index b9b1213..ee000a5 100644 --- a/src/structure/interfaces/Module.js +++ b/src/structure/interfaces/Module.js @@ -9,7 +9,7 @@ class Module extends Component { super(manager, { id: opts.name, - type: 'module' + _type: 'module' }); this.manager = manager; diff --git a/src/structure/interfaces/Observer.js b/src/structure/interfaces/Observer.js index df086ce..8970134 100644 --- a/src/structure/interfaces/Observer.js +++ b/src/structure/interfaces/Observer.js @@ -7,7 +7,7 @@ class Observer extends Component { super(client, { id: options.name, - type: 'observer', + _type: 'observer', guarded: options.guarded, disabled: options.disabled }); diff --git a/src/structure/interfaces/SlashCommand.js b/src/structure/interfaces/SlashCommand.js new file mode 100644 index 0000000..a7a445c --- /dev/null +++ b/src/structure/interfaces/SlashCommand.js @@ -0,0 +1,40 @@ +const Command = require('./Command.js'); +const { Commands: CommandsConstant } = require('../../constants/'); + +class SlashCommand extends Command { + + constructor(client, options = {}) { + if(!options) return null; + + super(client, { + name: options.name, + module: options.module, + description: options.description, + tags: options.tags, + restricted: options.restricted, + guildOnly: options.guildOnly, + archivable: options.archivable, + disabled: options.disabled, + guarded: options.guarded, + slash: true + }); + + this.type = Object.keys(CommandsConstant.ApplicationCommandTypes).includes(options.type) ? options.type : 'CHAT_INPUT'; + this.options = options.options || []; + this.defaultPermission = options.defaultPermission || {}; + + } + + get json() { + return { + name: this.name, + description: this.description, + type: CommandsConstant.ApplicationCommandTypes[this.type], + options: this.options, + defaultPermission: this.defaultPermission + }; + } + +} + +module.exports = SlashCommand; \ No newline at end of file diff --git a/src/structure/interfaces/index.js b/src/structure/interfaces/index.js index 30efee5..450e78a 100644 --- a/src/structure/interfaces/index.js +++ b/src/structure/interfaces/index.js @@ -2,6 +2,7 @@ module.exports = { Component: require('./Component.js'), Observer: require('./Observer.js'), Module: require('./Module.js'), + SlashCommand: require('./SlashCommand.js'), Command: require('./Command.js'), Thing: require('./Thing.js') }; \ No newline at end of file