require('colors')
const Discord = require('discord.js')
const util = require('util')
const moment = require('moment')
const CommandManager = require('./commands')
const GuildManager = require('./guilds')
const ModuleManager = require('./modules')
const PermissionsManager = require('./permissions')
const DataStore = require('./data')
const SettingsManager = require('./settings')
const AudioPlayer = require('./audioPlayer')
const LocaleManager = require('./locales')
const pkg = require('../package.json')
const EventEmitter = require('events').EventEmitter
/**
* The mother of all seals.
*/
class Azarasi {
/**
* Instantiates a new Bot.
* @param {object} properties - The properties object.
* @param {string} properties.prefix - Default bot prefix (REQUIRED)
* @param {string} properties.token - Bot token (REQUIRED)
* @param {boolean} properties.selfBot - Defines this bot as a selfbot
* @param {string} properties.publicPrefix - Public Prefix (SelfBots only)
* @param {string[]} properties.owner - Bot owner user IDs
* @param {string[]} properties.admins - Global admin user IDs
* @param {string[]} properties.adminRoles - Admin role names
* @param {string[]} properties.djRoles - "DJ" role names
* @param {string[]} properties.blacklist - Blacklisted User IDs
* @param {string} properties.modulePath - Path to load modules from
* @param {string} properties.ffmpegBin - Path to the FFMPEG binary (will use the global PATH if not set)
* @param {string} properties.dbFile - Database file.
* @param {string} properties.dbPort - Database port.
* @param {boolean} properties.debug - True to enable debug mode
* @param {boolean} properties.watch - True to enable automatic hot-reloading of modules
* @param {string} properties.localePath - Path to load locales from
* @param {string} properties.locale - Default locale
*/
constructor (properties) {
global.Core = this
/** The properties object */
this.properties = properties
// Some checks
if (!this.properties) throw new Error('No properties object.')
if (!this.properties.prefix) throw new Error('No prefix set.')
if (!this.properties.token) throw new Error('Missing bot token.')
/** The Discord.js Client */
this.bot = new Discord.Client()
/**
* The data store
*/
this.data = new DataStore()
/**
* The guild manager
* @type {GuildManager}
*/
this.guilds = new GuildManager()
/**
* The permissions manager
* @type {PermissionsManager}
*/
this.permissions = new PermissionsManager()
/**
* The command manager
* @type {CommandManager}
*/
this.commands = new CommandManager()
/**
* The module manager
* @type {ModuleManager}
*/
this.modules = new ModuleManager()
/**
* The locale manager
* @type {LocaleManager}
*/
this.locales = new LocaleManager()
/**
* The settings manager
* @type {SettingsManager}
*/
this.settings = new SettingsManager()
/**
* Sharding client
* @type {Discord.ShardClientUtil}
*/
this.shard = this.bot.shard || { }
/**
* Main Event Emitter
*/
this.events = new EventEmitter()
this.events.setMaxListeners(1000)
/**
* Is the bot ready?
*/
this.ready = false
this.AudioPlayer = AudioPlayer
this.bot.on('ready', () => {
this.log(`Connected! (${this.bot.user.username}#${this.bot.user.discriminator}).`)
this.ready = true
if (this.properties.selfBot) {
this.permissions.owner.push(this.bot.user.id)
}
})
this.bot.on('message', msg => this.processMessage(msg))
this.bot.on('debug', m => this.log(m, 1))
this.bot.on('error', e => {
this.log('Something went wrong:', 2)
this.log(e, 2)
process.exit()
})
// hacks
if (Core.properties.ffmpegBin) {
require('prism-media/src/transcoders/ffmpeg/Ffmpeg').selectFfmpegCommand = () => {
return Core.properties.ffmpegBin
}
}
this.bootDate = moment()
this.version = pkg.version
}
/**
* Establishes connection with discord.
*/
establishConnection () {
this.bot.login(this.properties.token)
}
/**
* Processes messages.
* @param {object} msg - Discord.js message object
*/
processMessage (msg) {
// Check if the user isn't in the blacklist
if (this.properties.blacklist && this.properties.blacklist.indexOf(msg.author.id) >= 0) {
return
}
this.commands.processMessage(msg)
}
/**
* Logs stuff to the console.
* @param {number} type - 0 for important stuff, 1 for debug info, 2 for errors.
*/
log (message, type = 0) {
// Avoid useless logs when debug mode is disabled.
if (type === 1 && !this.properties.debug) return
const msg = (typeof message === 'string') ? message : util.inspect(message)
const t = moment()
const i = (this.shard.id || 0).toString()
let prefix = `[${t.format('YY/MM/DD@').dim.cyan}${t.format('HH:mm').cyan} ${i.yellow}]`
if (type >= 2) {
prefix = `[${t.format('YY/MM/DD@').dim.red}${t.format('HH:mm').red} ${i.yellow}]`
process.stderr.write(`${prefix} ${msg}\n`, 'utf8')
} else {
process.stdout.write(`${prefix} ${type === 1 ? msg.gray : msg}\n`, 'utf8')
}
}
}
module.exports = Azarasi