2020-04-08 18:08:46 +02:00
|
|
|
const { Client } = require('discord.js');
|
2020-09-19 22:30:23 +02:00
|
|
|
const escapeRegex = require('escape-string-regexp');
|
2020-04-08 18:08:46 +02:00
|
|
|
|
2020-04-09 16:30:52 +02:00
|
|
|
const options = require('../../options.json');
|
|
|
|
|
2020-04-14 17:05:56 +02:00
|
|
|
const Registry = require('./Registry.js');
|
2020-04-08 18:08:46 +02:00
|
|
|
const EventHooker = require('./EventHooker.js');
|
2020-04-14 17:05:56 +02:00
|
|
|
const Dispatcher = require('./Dispatcher.js');
|
2020-04-08 18:08:46 +02:00
|
|
|
const Resolver = require('./Resolver.js');
|
2020-04-13 22:38:10 +02:00
|
|
|
const Logger = require('./Logger.js');
|
2020-08-08 00:21:28 +02:00
|
|
|
const LocaleLoader = require('../language/LocaleLoader.js');
|
2020-06-19 15:37:25 +02:00
|
|
|
const RateLimiter = require('./RateLimiter.js');
|
2020-04-08 18:08:46 +02:00
|
|
|
|
2020-08-08 00:21:28 +02:00
|
|
|
const StorageManager = require('../storage/StorageManager.js');
|
|
|
|
const ModerationManager = require('../moderation/ModerationManager.js');
|
|
|
|
|
2020-08-14 08:29:58 +02:00
|
|
|
const { Guild, GuildMember, User, Message, TextChannel, Role } = require('../../structure/extensions/'); //eslint-disable-line no-unused-vars
|
2020-04-09 23:08:28 +02:00
|
|
|
const { Command, Observer, Inhibitor, Setting } = require('../../structure/interfaces/');
|
2020-08-17 22:26:57 +02:00
|
|
|
const { DefaultGuild, DefaultUser } = require('../../util/defaults/');
|
2020-09-19 22:30:23 +02:00
|
|
|
const { Emojis } = require('../../util/');
|
2020-04-08 18:08:46 +02:00
|
|
|
|
|
|
|
class DiscordClient extends Client {
|
|
|
|
|
2020-04-09 16:30:52 +02:00
|
|
|
constructor(options) {
|
2020-04-08 18:08:46 +02:00
|
|
|
|
2020-04-09 16:30:52 +02:00
|
|
|
super(options.bot.clientOptions);
|
|
|
|
|
2020-04-09 23:08:28 +02:00
|
|
|
this.registry = new Registry(this);
|
2020-04-08 18:08:46 +02:00
|
|
|
this.eventHooker = new EventHooker(this);
|
|
|
|
this.dispatcher = new Dispatcher(this);
|
|
|
|
this.resolver = new Resolver(this);
|
2020-04-13 22:38:10 +02:00
|
|
|
this.logger = new Logger(this);
|
2020-04-19 12:12:10 +02:00
|
|
|
this.localeLoader = new LocaleLoader(this);
|
2020-06-19 15:37:25 +02:00
|
|
|
this.rateLimiter = new RateLimiter(this);
|
2020-04-08 18:08:46 +02:00
|
|
|
|
2020-08-08 00:21:28 +02:00
|
|
|
this.storageManager = new StorageManager(this, options.storage);
|
2020-06-02 12:09:28 +02:00
|
|
|
this.moderationManager = new ModerationManager(this);
|
|
|
|
|
2020-04-08 18:08:46 +02:00
|
|
|
this._options = options;
|
|
|
|
this._built = false;
|
2021-06-09 19:10:30 +02:00
|
|
|
this._devOnly = options.devOnly;
|
2020-04-08 18:08:46 +02:00
|
|
|
|
2020-08-08 00:21:28 +02:00
|
|
|
//TODO: Default config for users and guilds.
|
2020-08-17 22:26:57 +02:00
|
|
|
this._defaultConfig = {};
|
2020-08-16 09:27:49 +02:00
|
|
|
this._permissionCheck = null;
|
2020-04-16 14:37:04 +02:00
|
|
|
|
2020-08-14 16:13:29 +02:00
|
|
|
this._evals = new Map();
|
2020-04-16 14:37:04 +02:00
|
|
|
|
|
|
|
process.on('message', this._handleMessage.bind(this));
|
2021-06-09 16:36:55 +02:00
|
|
|
if (this._options.libDebug) this.on('debug', this.logger.debug.bind(this.logger));
|
2021-06-18 07:07:11 +02:00
|
|
|
|
|
|
|
this._activity = 0;
|
|
|
|
|
|
|
|
this.once('ready', () => {
|
|
|
|
this._setActivity();
|
|
|
|
|
2021-06-18 07:56:41 +02:00
|
|
|
setInterval(() => {
|
|
|
|
this._setActivity();
|
|
|
|
}, 1800000); // I think this is 30 minutes. I could be wrong.
|
2021-06-09 16:36:55 +02:00
|
|
|
});
|
2020-04-16 14:37:04 +02:00
|
|
|
|
2020-04-08 18:08:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async build() {
|
|
|
|
|
2020-04-09 23:08:28 +02:00
|
|
|
if(this._built) return undefined;
|
|
|
|
|
2020-07-23 22:40:20 +02:00
|
|
|
const beforeTime = Date.now();
|
2020-04-09 16:30:52 +02:00
|
|
|
await super.login(this._options.bot.token);
|
|
|
|
|
2020-05-07 01:26:16 +02:00
|
|
|
this.localeLoader.loadLanguages();
|
2020-04-19 12:12:10 +02:00
|
|
|
|
2020-08-08 00:21:28 +02:00
|
|
|
await this.storageManager.initialize();
|
|
|
|
|
2020-04-17 17:23:13 +02:00
|
|
|
await this.registry.loadComponents('components/inhibitors/', Inhibitor);
|
2020-04-09 23:08:28 +02:00
|
|
|
await this.registry.loadComponents('components/commands/', Command);
|
2020-04-17 17:23:13 +02:00
|
|
|
await this.registry.loadComponents('components/observers/', Observer);
|
2020-05-06 01:40:46 +02:00
|
|
|
await this.registry.loadComponents('components/settings/', Setting);
|
2020-04-09 16:30:52 +02:00
|
|
|
|
2020-06-16 00:15:13 +02:00
|
|
|
await this.moderationManager.initialize();
|
2020-04-09 23:08:28 +02:00
|
|
|
await this.dispatcher.dispatch();
|
2020-04-08 18:08:46 +02:00
|
|
|
|
2020-08-13 22:45:23 +02:00
|
|
|
this.logger.info(`Took ${Date.now()-beforeTime}ms to build the client.`);
|
2020-07-04 12:23:10 +02:00
|
|
|
|
2021-06-11 09:58:31 +02:00
|
|
|
process.on("unhandledRejection", (error) => {
|
2021-06-11 21:15:15 +02:00
|
|
|
this.logger.error(`Unhandled Promise Rejection:\n${error.stack || error}`);
|
2021-06-11 09:58:31 +02:00
|
|
|
});
|
|
|
|
|
2020-04-08 18:08:46 +02:00
|
|
|
this._built = true;
|
2020-05-21 12:47:58 +02:00
|
|
|
return this._built;
|
2020-04-08 18:08:46 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-09-19 17:37:46 +02:00
|
|
|
format(language, index, parameters = { }, code = false) {
|
|
|
|
|
|
|
|
let template = this.localeLoader.template(language, index); //.languages[language][index];
|
|
|
|
|
|
|
|
for(const emoji of Object.keys(Emojis)) {
|
|
|
|
parameters[`emoji_${emoji}`] = Emojis[emoji];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!template) {
|
|
|
|
return `**Missing language index \`${language} [${index}]\` in languages. Contact a bot developer about this.**`;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const [param, val] of Object.entries(parameters)) {
|
2021-05-03 16:56:09 +02:00
|
|
|
// eslint-disable-next-line require-unicode-regexp
|
2020-09-19 17:37:46 +02:00
|
|
|
template = template.replace(new RegExp(`{${escapeRegex(param.toLowerCase())}}`, 'gi'), val);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(code) {
|
|
|
|
try {
|
2021-05-03 16:56:09 +02:00
|
|
|
// eslint-disable-next-line no-eval
|
2020-09-19 17:37:46 +02:00
|
|
|
template = eval(template);
|
|
|
|
} catch(error) {
|
2021-06-11 21:15:15 +02:00
|
|
|
this.logger.error(`Error in locale ${language}:${index} while executing code.\n${error.stack || error}`);
|
2020-09-19 17:37:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return template;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-08-14 16:13:29 +02:00
|
|
|
async resolveUsers() {
|
|
|
|
|
2021-05-04 16:16:52 +02:00
|
|
|
// eslint-disable-next-line prefer-rest-params
|
2020-08-14 16:13:29 +02:00
|
|
|
return this.resolver.resolveUsers(...arguments);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async resolveUser() {
|
|
|
|
|
2021-05-04 16:16:52 +02:00
|
|
|
// eslint-disable-next-line prefer-rest-params
|
2020-08-14 16:13:29 +02:00
|
|
|
return this.resolver.resolveUser(...arguments);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-07-23 22:40:20 +02:00
|
|
|
async _handleMessage(message) {
|
2020-08-08 00:21:28 +02:00
|
|
|
//Handle misc. messages.
|
2020-08-14 16:13:29 +02:00
|
|
|
if (message._evalResult) this.evalResult(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
async managerEval(script) {
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
this._evals.set(script, { resolve, reject });
|
|
|
|
process.send({ _mEval: true, script });
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
evalResult({ script, result, error }) {
|
|
|
|
|
|
|
|
const promise = this._evals.get(script);
|
|
|
|
if (result) promise.resolve(result);
|
|
|
|
else promise.reject(error);
|
|
|
|
this._evals.delete(script);
|
|
|
|
|
2020-07-23 22:40:20 +02:00
|
|
|
}
|
|
|
|
|
2020-08-17 22:26:57 +02:00
|
|
|
defaultConfig(type) {
|
|
|
|
if(this._defaultConfig[type]) return this._defaultConfig[type];
|
|
|
|
const settings = this.registry.components.filter((c) => c.type === 'setting' && c.resolve === type);
|
|
|
|
let def = type === 'GUILD' ? DefaultGuild : DefaultUser;
|
2020-05-06 01:40:46 +02:00
|
|
|
for(const setting of settings.values()) {
|
|
|
|
if(setting.default !== null) {
|
|
|
|
def = {
|
|
|
|
...def,
|
|
|
|
...setting.default
|
2020-05-07 01:26:16 +02:00
|
|
|
};
|
2020-05-06 01:40:46 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-17 22:26:57 +02:00
|
|
|
this._defaultConfig[type] = def;
|
2020-05-06 01:40:46 +02:00
|
|
|
return def;
|
2020-07-28 05:00:24 +02:00
|
|
|
|
2020-05-06 01:40:46 +02:00
|
|
|
}
|
|
|
|
|
2020-08-16 09:27:49 +02:00
|
|
|
get permissions() {
|
|
|
|
if(this._permissionCheck) return this._permissionCheck;
|
|
|
|
return this._permissionCheck = this.registry.components.get('inhibitor:permissions'); //eslint-disable-line no-return-assign
|
|
|
|
}
|
|
|
|
|
2020-07-26 22:09:25 +02:00
|
|
|
get prefix() {
|
2021-06-11 21:19:50 +02:00
|
|
|
return this._options.bot.prefix;
|
2020-07-26 22:09:25 +02:00
|
|
|
}
|
|
|
|
|
2020-08-14 21:45:03 +02:00
|
|
|
get storage() {
|
|
|
|
return this.storageManager;
|
2020-05-06 01:40:46 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 07:07:11 +02:00
|
|
|
async _setActivity() {
|
|
|
|
const activities = {
|
|
|
|
0: async () => {
|
|
|
|
const guildCount = (await this.shard.broadcastEval('this.guilds.cache.size')).reduce((p, v) => p+v, 0);
|
|
|
|
this.user.setActivity(`${guildCount} servers`, { type: 'WATCHING' });
|
|
|
|
},
|
|
|
|
1: async () => {
|
|
|
|
const userCount = (await this.shard.broadcastEval('this.users.cache.size')).reduce((p, v) => p+v, 0);
|
|
|
|
this.user.setActivity(`to ${userCount} users`, { type: 'LISTENING' });
|
|
|
|
},
|
|
|
|
2: async () => {
|
|
|
|
this.user.setActivity("to -help", { type: 'LISTENING' });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
await activities[this._activity]();
|
|
|
|
if(this._activity === Math.max(...Object.keys(activities))) this._activity = 0;
|
|
|
|
else this._activity++;
|
2021-06-09 02:39:49 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-08 18:08:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = DiscordClient;
|
|
|
|
|
2020-04-09 16:30:52 +02:00
|
|
|
const client = new DiscordClient(options);
|
2021-06-11 09:58:31 +02:00
|
|
|
client.build();
|