managers_interaction_ContextInteractionManager.js
'use strict';
const readDirectory = require('node:util').promisify(require('node:fs').readdir);
const statDirectory = require('node:util').promisify(require('node:fs').stat);
const { Collection, Guild } = require('discord.js');
const { DisGroupDevError, Messages } = require('../../errors/DisGroupDevError');
const ContextInteraction = require('../../structures/interaction/ContextInteraction');
/**
* The context interaction manager.
* @class
*/
class ContextInteractionManager {
/**
* The constructor of the context interaction manager class.
* @param {Client} client The client
* @param {InteractionManager} interactionManager The interaction manager
*/
constructor(client, interactionManager) {
/**
* The cache with all context interactions
* @type {Collection<String, ContextInteraction>}
* @public
*/
this.cache = new Collection();
/**
* The client
* @type {Client}
* @public
*/
this.client = client;
/**
* The interaction manager
* @type {InteractionManager}
* @public
*/
this.manager = interactionManager;
}
/**
* Deploys one specific context interaction
* @param {ContextInteraction} contextInteraction The context interaction to deploy
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
deploy(contextInteraction) {
return new Promise(async (resolve, reject) => {
if (!(contextInteraction instanceof ContextInteraction)) reject(new DisGroupDevError(Messages.NOT_INSTANCE_OF(contextInteraction, ContextInteraction)));
if (!contextInteraction.deployEnabled) reject(new DisGroupDevError(Messages.NOT_ENABLED));
try {
/** @type {Guild[]} */
let guilds = [];
for (const guildId of this.manager.options.guildIDs) {
const guild = this.client.guilds.resolve(guildId);
if (!guild || !(guild instanceof Guild)) reject(new DisGroupDevError(Messages.UNRESOLVABLE_GUILD(guildId)));
guilds.push(guild);
}
if (contextInteraction.guildOnly) {
for (const guild of guilds) {
const guildCommand = await guild.commands.create({
name: contextInteraction.name,
nameLocalizations: contextInteraction.nameLocalizations,
defaultMemberPermissions: contextInteraction.defaultMemberPermissions,
type: contextInteraction.type,
defaultPermission: contextInteraction.defaultEnabled,
});
contextInteraction.id = guildCommand.id;
/**
* Emitted when a context interaction is deployed.
* @event InteractionManager#contextInteractionDeploy
* @param {ContextInteraction} contextInteraction The context interaction
* @public
*/
this.manager.emit('contextInteractionDeploy', contextInteraction);
}
} else {
const applicationCommand = await this.client.application.commands.create({
name: contextInteraction.name,
nameLocalizations: contextInteraction.nameLocalizations,
defaultMemberPermissions: contextInteraction.defaultMemberPermissions,
dmPermission: contextInteraction.dmEnabled,
type: contextInteraction.type,
defaultPermission: contextInteraction.defaultEnabled,
});
contextInteraction.id = applicationCommand.id;
/**
* Emitted when a context interaction is deployed.
* @event InteractionManager#contextInteractionDeploy
* @param {ContextInteraction} contextInteraction The context interaction
* @public
*/
this.manager.emit('contextInteractionDeploy', contextInteraction);
}
} catch (e) {
throw new DisGroupDevError(e);
}
resolve(true);
});
}
/**
* Deploys all context interactions
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
deployAll() {
return new Promise(async resolve => {
try {
for (const contextInteraction of this.cache) {
await this.deploy(contextInteraction[1]);
}
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
/**
* Loads one specific context interaction
* @param {String} path The path to the context interaction
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
load(path) {
return new Promise((resolve, reject) => {
try {
/** @type {ContextInteraction} */
const contextInteraction = new (require(path))(this.client, this.manager);
if (!contextInteraction.enabled) return;
contextInteraction.location = path;
if (contextInteraction.init && typeof contextInteraction.init === 'function') contextInteraction.init();
if (!contextInteraction.execute || typeof contextInteraction.execute !== 'function') reject(new DisGroupDevError(Messages.INVALID_EXECUTE(contextInteraction.name)));
this.cache.set(contextInteraction.name, contextInteraction);
/**
* Emitted when a context interaction is loaded.
* @event InteractionManager#contextInteractionLoad
* @param {ContextInteraction} contextInteraction The context interaction
* @public
*/
this.manager.emit('contextInteractionLoad', contextInteraction);
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
/**
* Loads all context interactions
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
loadAll() {
return new Promise(async resolve => {
try {
const contextInteractionDirectory = await readDirectory(this.manager.options.locationContextInteractions);
for (const contextInteractionDirectoryCategoryOrFile of contextInteractionDirectory) {
const contextInteractionDirectoryStat = await statDirectory(require('node:path').resolve(this.manager.options.locationContextInteractions, contextInteractionDirectoryCategoryOrFile));
if (contextInteractionDirectoryStat.isDirectory()) {
const contextInteractionDirectoryCategory = await readDirectory(require('node:path').resolve(this.manager.options.locationContextInteractions, contextInteractionDirectoryCategoryOrFile));
for (const contextInteractionDirectoryCategoryFile of contextInteractionDirectoryCategory) {
await this.load(`${this.manager.options.locationContextInteractions}/${contextInteractionDirectoryCategoryOrFile}/${contextInteractionDirectoryCategoryFile}`);
}
} else if (contextInteractionDirectoryStat.isFile()) {
await this.load(`${this.manager.options.locationContextInteractions}/${contextInteractionDirectoryCategoryOrFile}`);
}
}
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
/**
* Reloads one specific context interaction
* @param {String} name The name of the context interaction
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
reload(name) {
return new Promise(async (resolve, reject) => {
if (!this.cache.has(name)) reject(new DisGroupDevError(Messages.CONTEXT_INTERACTION_NOT_FOUND(name)));
const { location } = require(this.cache.get(name));
try {
await this.unload(name);
await this.load(location);
const contextInteraction = this.cache.get(name);
/**
* Emitted when a context interaction is reloaded.
* @event InteractionManager#contextInteractionReload
* @param {ContextInteraction} contextInteraction The context interaction
* @public
*/
this.manager.emit('contextInteractionReload', contextInteraction);
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
/**
* Reloads all context interactions
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
reloadAll() {
return new Promise(async resolve => {
try {
for (const contextInteraction of this.cache) {
await this.unload(contextInteraction[1].name);
}
await this.loadAll();
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
/**
* Unloads one specific context interaction
* @param {String} name The name of the context interaction
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
unload(name) {
return new Promise((resolve, reject) => {
if (!this.cache.has(name)) reject(new DisGroupDevError(Messages.CONTEXT_INTERACTION_NOT_FOUND(name)));
try {
delete require.cache[require.resolve(this.cache.get(name).location)];
this.cache.delete(name);
/**
* Emitted when a context interaction is unloaded.
* @event InteractionManager#contextInteractionUnload
* @param {String} name The name of the context interaction
* @public
*/
this.manager.emit('contextInteractionUnload', name);
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
/**
* Unloads all context interactions
* @returns {Promise<Boolean|DisGroupDevError>}
* @public
*/
unloadAll() {
return new Promise(async resolve => {
try {
for (const contextInteraction of this.cache) {
await this.unload(contextInteraction[1].name);
}
resolve(true);
} catch (e) {
throw new DisGroupDevError(e);
}
});
}
}
module.exports = ContextInteractionManager;