const Discord = require('discord.js')
/**
* Controller for {@link https://discord.js.org/#/docs/main/stable/general/welcome|discord.js}
*
* @class
* @extends Map
*/
class DiscordController extends Map {
/**
* Initializes a new DiscordController
*
* @param {Object} config configuration object
* @param {Esdi} config.server Esdi server instance
* @param {String} [config.discordToken = process.env.DISCORD_TOKEN] token for Discord bot
* @param {String} [config.botOwner = '139293101767262208'] Discord ID of bot instance owner
* @memberof DiscordController
*/
init ({ server, discordToken = process.env.DISCORD_TOKEN, botOwner = '139293101767262208' }) {
this.server = server
this.token = discordToken
this.botOwner = botOwner
this.discordJs = Discord
}
/**
* Starts the DiscordController
*
* @listens Esdi#start
* @memberof DiscordController
*/
start () {
console.log('[#] Starting DiscordController...')
/**
* discord.js Client
* @external Client
* @see https://discord.js.org/#/docs/main/stable/class/Client
*/
this.client = new Discord.Client()
this.client.discordController = this
/**
* discord.js Message
* @external Message
* @see https://discord.js.org/#/docs/main/stable/class/Message
*/
this.client.on('message', message => {
// determine command prefix
const prefix = this.server.controllers.get('CommandController').determinePrefix(message)
if (message.author.bot || !prefix) return
const args = message.content.toLowerCase().slice(prefix.length).trim().split(/ +/)
const commandName = args.shift().toLowerCase()
const command = this.server.controllers.get('CommandController').findCommand(commandName)
if (!command) return
this.server.controllers.get('CommandController').executeCommand({ command, args, message })
})
// register Events to the bot
this.server.controllers.get('EventController').registerDiscordEvents(this.client)
this.login()
}
/**
* Stops the DiscordController
*
* @listens Esdi#stop
* @memberof DiscordController
*/
stop () {
console.log('[#] Stopping DiscordController...')
delete this.id
this.client.destroy()
}
/**
* Logs in the {@link external:Client|Client} with a token
*
* @memberof DiscordController
*/
login () {
this.client.login(this.token)
.then(() => console.log('[D] Successfully logged bot in to Discord'))
.catch(e => { throw e.message })
}
/**
* Returns an array of {@link https://discord.js.org/#/docs/main/stable/typedef/EmbedField|EmbedField} values from a string for a {@link https://discord.js.org/#/docs/main/stable/class/MessageEmbed|discord.js MessageEmbed}
*
* @param {String[]} embedFieldValues array of values for EmbedFields
* @param {String} content content for EmbedFields
* @memberof DiscordController
*/
buildEmbedFieldValues (embedFieldValues, content) {
if (!embedFieldValues[0]) embedFieldValues[0] = ''
const i = embedFieldValues.length - 1
if (embedFieldValues[i].length + content.length <= 1024) {
embedFieldValues[i] += content
} else {
if (!embedFieldValues[i + 1]) embedFieldValues[i + 1] = ''
embedFieldValues[i + 1] += content
}
}
/**
* Returns {@link https://discord.js.org/#/docs/main/stable/typedef/EmbedField|EmbedFields} for a {@link https://discord.js.org/#/docs/main/stable/class/MessageEmbed|discord.js MessageEmbed}
*
* @param {String} embedFieldName name of EmbedField
* @param {String[]} embedFieldValues array of values for EmbedFields
* @returns {external:EmbedField[]} array of discord.js EmbedFields
* @memberof DiscordController
*/
buildEmbedFields (embedFieldName, embedFieldValues) {
const embedFields = []
for (let i = 0; i <= embedFieldValues.length - 1; i++) {
embedFields.push({
name: `${embedFieldName}${i !== 0 ? ' (cont.)' : ''}`,
value: embedFieldValues[i]
})
}
return embedFields
}
/**
* Returns a {@link https://discord.js.org/#/docs/main/stable/class/MessageEmbed|discord.js MessageEmbed}
*
* @param {Object} embedConfig configuration object
* @param {String} embedConfig.title MessageEmbed title
* @param {String} embedConfig.description MessageEmbed description
* @param {String} [embedConfig.hexColor = '#2f9d8c'] hex color code for MessageEmbed accent
* @param {String} embedConfig.footerTextType type of Esdi component posting the MessageEmbed (e.g., Command, Hook, Event)
* @param {external:EmbedField[]} [embedConfig.fields = []] array of discord.js EmbedFields for MessageEmbed
* @param {external:MessageEmbedThumbnail} embedConfig.thumbnail MessageEmbedThumbnail object for MessageEmbed
* @param {Date} embedConfig.timestamp timestamp for for MessageEmbed
* @param {external:MessageEmbedAuthor} embedConfig.author MessageEmbedAuthor for MessageEmbed
* @returns {external:MessageEmbed} discord.js MessageEmbed
* @memberof DiscordController
*/
buildEmbed ({ title, description, url, hexColor = '#2f9d8c', footerTextType, fields = [], thumbnail, timestamp, author }) {
// only allow up to 25 fields
const validatedFields = fields.slice(0, 25)
return new Discord.MessageEmbed({
author,
title,
description,
url,
color: Discord.Util.resolveColor(hexColor),
timestamp: timestamp || Date.now(),
footer: {
icon_url: 'https://user-images.githubusercontent.com/7295363/101524119-6169a080-393e-11eb-8006-6816e2c5f413.gif',
text: `${footerTextType} by Esdi 🤍`
},
fields: validatedFields,
thumbnail
})
}
/**
* Returns a {@link https://discord.js.org/#/docs/main/stable/class/MessageEmbed|discord.js MessageEmbed} that reports the memory and processor usage of the server's process along with its uptime and Discord stats
*
* @param {Object} statusEmbedConfig configuration object
* @param {String} statusEmbedConfig.title MessageEmbed title
* @param {String} statusEmbedConfig.footerTextType type of Esdi component calling this method (e.g., Command, Event)
* @returns {external:MessageEmbed} discord.js MessageEmbed
* @memberof DiscordController
*/
buildStatusEmbed ({ title, footerTextType }) {
const fields = []
const uptime = this.server.determineUptime()
fields.push({
name: '__Uptime__',
value: `\`${uptime}\``,
inline: true
})
const rss = this.server.determineMemory()
fields.push({
name: '__Memory__',
value: `\`${rss}\``,
inline: true
})
const processor = this.server.determineProcessor()
fields.push({
name: '__Processor__',
value: `\`${processor}\``,
inline: true
})
fields.push({
name: '__Servers__',
value: `\`${this.server.controllers.get('GuildController').size}\``,
inline: true
})
fields.push({
name: '__Users__',
value: `\`${this.server.controllers.get('UserController').size}\``,
inline: true
})
fields.push({
name: '__Version__',
value: '`' + require('./../package').version + '`',
inline: true
})
const colors = ['blue', 'gray', 'green', 'pink', 'brown', 'yellow']
const hexColors = {
blue: '#788eb7',
gray: '#808080',
green: '#77bb74',
pink: '#c78c9f',
brown: '#aa8a85',
yellow: '#bd9e73'
}
const images = {
blue: 'https://user-images.githubusercontent.com/7295363/103381612-22dc8700-4aa1-11eb-940e-ef27d9cc9ea2.gif',
gray: 'https://user-images.githubusercontent.com/7295363/103381613-23751d80-4aa1-11eb-818d-6696a6f67b4f.gif',
green: 'https://user-images.githubusercontent.com/7295363/103381614-240db400-4aa1-11eb-8435-1976ec95dd9a.gif',
pink: 'https://user-images.githubusercontent.com/7295363/103381617-240db400-4aa1-11eb-9579-6fd6f5ace65e.gif',
brown: 'https://user-images.githubusercontent.com/7295363/103381618-24a64a80-4aa1-11eb-9206-8916473d9a5f.gif',
yellow: 'https://user-images.githubusercontent.com/7295363/103381620-24a64a80-4aa1-11eb-99e6-db45b15a1c40.gif'
}
const random = Math.floor(Math.random() * colors.length)
const color = colors[random]
// build message embed
return this.buildEmbed({
title,
footerTextType,
fields,
hexColor: hexColors[color],
thumbnail: {
url: images[color]
}
})
}
}
// factory
module.exports = new DiscordController()