2017-10-02 01:19:10 +03:00
|
|
|
const CoreUtil = require("./Util.js");
|
2017-12-07 02:11:14 +02:00
|
|
|
const Camo = require("camo");
|
|
|
|
const CronJob = require("cron").CronJob;
|
|
|
|
const Discord = require("discord.js");
|
|
|
|
const HandleGuildMessage = require("./HandleGuildMessage");
|
2017-09-24 23:07:35 +03:00
|
|
|
const InternalConfig = require("./internal-config.json");
|
2017-12-07 02:11:14 +02:00
|
|
|
const RequireAll = require("require-all");
|
|
|
|
const Util = require("./Util.js");
|
|
|
|
|
|
|
|
let neDB;
|
2017-09-24 23:07:35 +03:00
|
|
|
|
|
|
|
module.exports = class Client extends Discord.Client {
|
2017-12-07 02:11:14 +02:00
|
|
|
/**
|
|
|
|
* Construct a new Discord.Client with some added functionality
|
|
|
|
* @param {string} token bot token
|
|
|
|
* @param {string} commandsDir location of dir containing commands .js files
|
|
|
|
* @param {*} guildDataModel GuildData model to be used for app; must extend BaseGuildData
|
|
|
|
*/
|
2017-12-09 07:39:04 +02:00
|
|
|
constructor(token, commandsDir, guildDataModel) {
|
2018-01-03 03:45:44 +02:00
|
|
|
super({
|
2018-01-14 21:25:56 +02:00
|
|
|
messageCacheMaxSize: 16
|
2018-01-03 03:45:44 +02:00
|
|
|
});
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-09-24 23:07:35 +03:00
|
|
|
this._token = token;
|
|
|
|
this.commandsDir = commandsDir;
|
2017-09-20 01:26:30 +03:00
|
|
|
this.guildDataModel = guildDataModel;
|
|
|
|
|
2017-09-24 23:07:35 +03:00
|
|
|
this.commands = RequireAll(this.commandsDir);
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
this.on("ready", this._onReady);
|
|
|
|
this.on("message", this._onMessage);
|
|
|
|
this.on("debug", this._onDebug);
|
|
|
|
this.on("guildCreate", this._onGuildCreate);
|
|
|
|
this.on("guildDelete", this._onGuildDelete);
|
2017-12-07 02:19:16 +02:00
|
|
|
process.on("uncaughtException", err => this._onUnhandledException(this, err));
|
2017-09-20 01:26:30 +03:00
|
|
|
}
|
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
_onReady() {
|
2017-10-19 02:14:01 +03:00
|
|
|
this.user.setGame(InternalConfig.website.replace(/^https?:\/\//, ""));
|
2017-09-24 23:07:35 +03:00
|
|
|
CoreUtil.dateLog(`Registered bot ${this.user.username}`);
|
2017-11-12 21:44:19 +02:00
|
|
|
|
2017-12-08 02:07:02 +02:00
|
|
|
this.removeDeletedGuilds();
|
2017-09-24 23:07:35 +03:00
|
|
|
}
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
_onMessage(message) {
|
|
|
|
if (message.channel.type === "text" && message.member)
|
|
|
|
HandleGuildMessage(this, message, this.commands);
|
2017-09-24 23:07:35 +03:00
|
|
|
}
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
_onDebug(info) {
|
2017-11-20 03:08:37 +02:00
|
|
|
info = info.replace(/Authenticated using token [^ ]+/, "Authenticated using token [redacted]");
|
2017-11-27 01:35:51 +02:00
|
|
|
if (!InternalConfig.debugIgnores.some(x => info.startsWith(x)))
|
|
|
|
CoreUtil.dateDebug(info);
|
2017-09-24 23:07:35 +03:00
|
|
|
}
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
_onGuildCreate(guild) {
|
2017-11-11 03:28:38 +02:00
|
|
|
CoreUtil.dateLog(`Added to guild ${guild.name}`);
|
|
|
|
}
|
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
_onGuildDelete(guild) {
|
2017-12-08 00:22:00 +02:00
|
|
|
this.guildDataModel.findOneAndDelete({ guildID: guild.id });
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
CoreUtil.dateLog(`Removed from guild ${guild.name}, removing data for this guild`);
|
2017-09-24 23:07:35 +03:00
|
|
|
}
|
2017-12-07 02:19:16 +02:00
|
|
|
|
|
|
|
_onUnhandledException(client, err) {
|
|
|
|
CoreUtil.dateError("Unhandled exception!\n", err);
|
|
|
|
CoreUtil.dateLog("Destroying existing client...");
|
|
|
|
client.destroy().then(() => {
|
|
|
|
CoreUtil.dateLog("Client destroyed, recreating...");
|
|
|
|
setTimeout(() => client.login(client._token), InternalConfig.reconnectTimeout);
|
|
|
|
});
|
|
|
|
}
|
2017-12-08 02:07:02 +02:00
|
|
|
|
|
|
|
bootstrap() {
|
|
|
|
Camo.connect("nedb://guilds-data").then(db => {
|
|
|
|
neDB = db;
|
|
|
|
new CronJob(InternalConfig.dbCompactionSchedule, compactCollections, null, true);
|
|
|
|
|
|
|
|
this.emit("beforeLogin");
|
|
|
|
this.login(this._token);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
removeDeletedGuilds() {
|
|
|
|
this.guildDataModel.find().then(guildDatas => {
|
|
|
|
for (let guildData of guildDatas)
|
|
|
|
if (!this.guilds.get(guildData.guildID))
|
|
|
|
guildData.delete();
|
|
|
|
});
|
|
|
|
}
|
2017-12-07 02:11:14 +02:00
|
|
|
};
|
2017-09-20 01:26:30 +03:00
|
|
|
|
2017-12-07 02:11:14 +02:00
|
|
|
function compactCollections() {
|
|
|
|
/*I realise it is a bit of a cheat to just access _collections in this manner, but in the absence of
|
|
|
|
camo actually having any kind of solution for this it's the easiest method I could come up with.
|
|
|
|
Maybe at some point in future I should fork camo and add this feature. The compaction function is NeDB only
|
|
|
|
and camo is designed to work with both NeDB and MongoDB, which is presumably why it doesn't alraedy exist */
|
|
|
|
for (let collectionName of Object.keys(neDB._collections))
|
|
|
|
neDB._collections[collectionName].persistence.compactDatafile();
|
|
|
|
}
|