git subrepo commit (merge) discord-bot-core
subrepo: subdir: "discord-bot-core" merged: "77cb9dd" upstream: origin: "git@github.com:benji7425/discord-bot-core.git" branch: "master" commit: "8e6d6ce" git-subrepo: version: "0.3.1" origin: "???" commit: "???"
This commit is contained in:
parent
6398e39359
commit
8414532044
|
@ -6,7 +6,7 @@
|
|||
[subrepo]
|
||||
remote = git@github.com:benji7425/discord-bot-core.git
|
||||
branch = master
|
||||
commit = c4f07d0a8d4585083c3f167c1dce55cbeeda05d2
|
||||
commit = 8e6d6ce99e581f5ac5fb899112ef33bcf3e16a34
|
||||
parent = 341964a90ddca9afc684fd9331fc4177b8b68c04
|
||||
method = merge
|
||||
cmdver = 0.3.1
|
||||
|
|
72
discord-bot-core/bootstrapper.js
vendored
72
discord-bot-core/bootstrapper.js
vendored
|
@ -1,72 +0,0 @@
|
|||
//node imports
|
||||
const FileSystem = require("fs"); //manage files
|
||||
const Util = require("util");
|
||||
|
||||
//external lib imports
|
||||
const Discord = require("discord.js");
|
||||
const JsonFile = require("jsonfile"); //save/load data to/from json
|
||||
|
||||
const Config = require("./config.json");
|
||||
const ParentPackageJSON = require("../package.json"); //used to provide some info about the bot
|
||||
const DiscordUtil = require("./util.js"); //some discordjs helper functions of mine
|
||||
const MessageHandler = require("./message-handler.js");
|
||||
|
||||
function bootstrap(token, component, guildDataModel, commands) {
|
||||
process.on("uncaughtException", (err) => {
|
||||
DiscordUtil.dateError("Uncaught exception!", err);
|
||||
});
|
||||
|
||||
const client = new Discord.Client();
|
||||
|
||||
client.on("ready", () => {
|
||||
onReady(client, component, guildDataModel, commands);
|
||||
|
||||
client.user.setGame("benji7425.github.io");
|
||||
DiscordUtil.dateLog("Registered bot " + client.user.username);
|
||||
});
|
||||
|
||||
client.on("disconnect", eventData => {
|
||||
DiscordUtil.dateError("Bot was disconnected!", eventData.code, eventData.reason);
|
||||
});
|
||||
|
||||
client.login(token);
|
||||
}
|
||||
|
||||
function onReady(client, component, guildDataModel, commands) {
|
||||
const saveFile = Util.format(Config.saveFile, ParentPackageJSON.name + "");
|
||||
|
||||
const guildsData =
|
||||
FileSystem.existsSync(saveFile) ?
|
||||
fromJSON(JsonFile.readFileSync(saveFile), guildDataModel) : {};
|
||||
|
||||
const writeFile = () =>
|
||||
JsonFile.writeFile(
|
||||
saveFile,
|
||||
guildsData,
|
||||
err => {
|
||||
if (err) DiscordUtil.dateError("Error writing file", err);
|
||||
});
|
||||
|
||||
setInterval(() => writeFile(), Config.saveIntervalSec * 1000);
|
||||
|
||||
client.on("message", message => {
|
||||
if (message.author.id !== client.user.id) {
|
||||
if (message.channel.type === "dm")
|
||||
MessageHandler.handleDirectMessage({ client, message });
|
||||
else if (message.channel.type === "text" && message.member)
|
||||
MessageHandler.handleTextMessage({ client, commands, message, guildDataModel, guildsData, component, writeFile });
|
||||
}
|
||||
});
|
||||
|
||||
component.onReady(client, guildsData)
|
||||
.then(() => writeFile())
|
||||
.catch(err => DiscordUtil.dateError(err));
|
||||
}
|
||||
|
||||
function fromJSON(json, guildDataModel) {
|
||||
const guildsData = Object.keys(json);
|
||||
guildsData.forEach(guildID => { json[guildID] = new guildDataModel(json[guildID]); });
|
||||
return json;
|
||||
}
|
||||
|
||||
module.exports = bootstrap;
|
109
discord-bot-core/client.js
Normal file
109
discord-bot-core/client.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
//node imports
|
||||
const FileSystem = require("fs"); //checking if files exist
|
||||
|
||||
//external lib imports
|
||||
const Discord = require("discord.js"); //discord interaction
|
||||
const JsonFile = require("jsonfile"); //saving to/reading from json
|
||||
|
||||
//component imports
|
||||
const DiscordUtil = require("./util.js"); //some helper methods
|
||||
const MessageHandler = require("./message-handler.js"); //message handling
|
||||
const Config = require("./internal-config.json"); //some configuration values
|
||||
|
||||
class CoreClient {
|
||||
/**
|
||||
* @param {string} token
|
||||
* @param {string} dataFile
|
||||
* @param {object} guildDataModel
|
||||
* @param {object[]} commands
|
||||
*/
|
||||
constructor(token, dataFile, commands, implementations, guildDataModel) {
|
||||
this.actual = new Discord.Client();
|
||||
|
||||
this.token = token;
|
||||
this.dataFile = dataFile;
|
||||
this.commands = commands;
|
||||
this.implementations = implementations;
|
||||
this.guildDataModel = guildDataModel;
|
||||
this.guildsData = FileSystem.existsSync(this.dataFile) ?
|
||||
fromJSON(JsonFile.readFileSync(this.dataFile), this.guildDataModel) : {};
|
||||
|
||||
process.on("uncaughtException", err => onUncaughtException(this, err));
|
||||
}
|
||||
|
||||
writeFile() {
|
||||
JsonFile.writeFile(
|
||||
this.dataFile,
|
||||
this.guildsData,
|
||||
err => {
|
||||
if (err) DiscordUtil.dateError("Error writing file", err);
|
||||
});
|
||||
}
|
||||
|
||||
bootstrap() {
|
||||
this.actual.on("ready", () => onReady(this));
|
||||
|
||||
this.actual.on("disconnect", eventData => DiscordUtil.dateError("Disconnect!", eventData.code, eventData.reason));
|
||||
|
||||
this.actual.on("message", message => {
|
||||
if (message.author.id === this.actual.user.id)
|
||||
return;
|
||||
if (message.channel.type === "dm")
|
||||
MessageHandler.handleDirectMessage(this, message);
|
||||
else if (message.channel.type === "text" && message.member)
|
||||
MessageHandler.handleTextMessage(this, message, this.guildsData)
|
||||
.then(msg => {
|
||||
if (msg) message.reply(msg);
|
||||
})
|
||||
.catch(err => {
|
||||
message.reply(err);
|
||||
DiscordUtil.dateError(`Command error in guild ${message.guild.name}\n`, err.message || err);
|
||||
})
|
||||
.then(() => this.writeFile());
|
||||
});
|
||||
|
||||
this.actual.login(this.token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} coreClient
|
||||
*/
|
||||
function onReady(coreClient) {
|
||||
coreClient.actual.user.setGame("benji7425.github.io");
|
||||
DiscordUtil.dateLog("Registered bot " + coreClient.actual.user.username);
|
||||
|
||||
setInterval(() => coreClient.writeFile(), Config.saveIntervalSec * 1000);
|
||||
|
||||
if (coreClient.implementations.onReady)
|
||||
coreClient.implementations.onReady(coreClient)
|
||||
.then(() => coreClient.writeFile())
|
||||
.catch(err => DiscordUtil.dateError(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} coreClient
|
||||
* @param {*} err
|
||||
*/
|
||||
function onUncaughtException(coreClient, err) {
|
||||
DiscordUtil.dateError(err.message || err);
|
||||
DiscordUtil.dateLog("Destroying existing client...");
|
||||
coreClient.actual.destroy().then(() => {
|
||||
DiscordUtil.dateLog("Client destroyed, recreating...");
|
||||
coreClient.actual = new Discord.Client();
|
||||
coreClient.bootstrap();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert json from file to a usable format
|
||||
* @param {object} json json from file
|
||||
* @param {*} guildDataModel
|
||||
*/
|
||||
function fromJSON(json, guildDataModel) {
|
||||
const guildsData = Object.keys(json);
|
||||
guildsData.forEach(guildID => { json[guildID] = new guildDataModel(json[guildID]); });
|
||||
return json;
|
||||
}
|
||||
|
||||
module.exports = CoreClient;
|
|
@ -1,7 +1,7 @@
|
|||
const Config = require("./config.json");
|
||||
const Config = require("./internal-config.json");
|
||||
|
||||
module.exports = {
|
||||
bootstrap: require("./bootstrapper.js"),
|
||||
Client: require("./client.js"),
|
||||
util: require("./util.js"),
|
||||
details: {
|
||||
website: Config.website,
|
||||
|
|
|
@ -4,60 +4,67 @@ const Util = require("util");
|
|||
//external lib imports
|
||||
const Discord = require("discord.js");
|
||||
|
||||
//lib components
|
||||
const Config = require("./config.json"); //generic lib configuration
|
||||
const DiscordUtil = require("./util.js"); //some discordjs helper functions of mine
|
||||
//component imports
|
||||
const Config = require("./internal-config.json"); //generic lib configuration
|
||||
const ParentPackageJSON = require("../package.json"); //used to provide some info about the bot
|
||||
|
||||
function handleDirectMessage(client, message) {
|
||||
message.reply(Util.format(Config.generic.defaultDMResponse, Config.generic.website, Config.generic.discordInvite));
|
||||
/**
|
||||
* Handle a direct message to the bot
|
||||
* @param {*} coreClient Core.Client
|
||||
* @param {*} message Discord.Message
|
||||
*/
|
||||
function handleDirectMessage(coreClient, message) {
|
||||
message.reply(Util.format(Config.defaultDMResponse, Config.website, Config.discordInvite));
|
||||
}
|
||||
|
||||
function handleTextMessage({ client, commands, message, guildDataModel, guildsData, component, writeFile }) {
|
||||
const isCommand = message.content.startsWith(message.guild.me.toString());
|
||||
let guildData = guildsData[message.guild.id];
|
||||
/**
|
||||
*
|
||||
* @param {*} coreClient Core.Client
|
||||
* @param {*} message Discord.Message
|
||||
* @param {*[]} guildsData GuildData[]
|
||||
*/
|
||||
function handleTextMessage(coreClient, message, guildsData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const isCommand = message.content.startsWith(message.guild.me.toString());
|
||||
let guildData = guildsData[message.guild.id];
|
||||
|
||||
if (!guildData)
|
||||
guildData = guildsData[message.guild.id] = new guildDataModel({ id: message.guild.id });
|
||||
if (!guildData)
|
||||
guildData = guildsData[message.guild.id] = new coreClient.guildDataModel({ id: message.guild.id });
|
||||
|
||||
if (isCommand) {
|
||||
Object.assign(commands, Config.commands);
|
||||
if (!isCommand)
|
||||
return coreClient.implementations.onTextMessage(message, guildData).then(msg => resolve(msg));
|
||||
|
||||
Object.assign(coreClient.commands, Config.commands);
|
||||
const userIsAdmin = message.member.permissions.has("ADMINISTRATOR");
|
||||
const botName = "@" + (message.guild.me.nickname || client.user.username);
|
||||
const { command, commandProp, params, expectedParamCount } = getCommandDetails(message, commands, userIsAdmin) || { command: null, commandProp: null, params: null, expectedParamCount: null };
|
||||
const invoke = component[commandProp];
|
||||
const botName = "@" + (message.guild.me.nickname || coreClient.actual.user.username);
|
||||
const { command, commandProp, params, expectedParamCount } = getCommandDetails(message, coreClient.commands, userIsAdmin) || { command: null, commandProp: null, params: null, expectedParamCount: null };
|
||||
const invoke = coreClient.implementations[commandProp];
|
||||
|
||||
if (!command || !params || isNaN(expectedParamCount))
|
||||
return;
|
||||
return reject(`'${message.content.split(" ")[1]}' is not a recognised command`);
|
||||
|
||||
switch (command) {
|
||||
case Config.commands.version:
|
||||
message.reply(`${ParentPackageJSON.name} v${ParentPackageJSON.version}`);
|
||||
break;
|
||||
case Config.commands.help:
|
||||
message.channel.send(createHelpEmbed(botName, commands, userIsAdmin));
|
||||
break;
|
||||
default:
|
||||
if (invoke && params.length >= expectedParamCount) {
|
||||
invoke({ params, guildData, botName, message, client })
|
||||
.then(msg => {
|
||||
message.reply(msg);
|
||||
writeFile();
|
||||
})
|
||||
.catch(err => {
|
||||
message.reply(err);
|
||||
DiscordUtil.dateError(err);
|
||||
});
|
||||
}
|
||||
else
|
||||
message.reply(`Incorrect syntax!\n**Expected:** *${botName} ${command.syntax}*\n**Need help?** *${botName} ${commands.help.command}*`);
|
||||
break;
|
||||
if (command === Config.commands.version)
|
||||
resolve(`${ParentPackageJSON.name} v${ParentPackageJSON.version}`);
|
||||
else if (command === Config.commands.help)
|
||||
message.channel.send(createHelpEmbed(botName, coreClient.commands, userIsAdmin));
|
||||
else {
|
||||
if (invoke && params.length >= expectedParamCount)
|
||||
invoke({ command, params: params, guildData, botName, message, coreClient })
|
||||
.then(msg =>
|
||||
resolve(msg))
|
||||
.catch(err => reject(err));
|
||||
else
|
||||
reject(`Incorrect syntax!\n**Expected:** *${botName} ${command.syntax}*\n**Need help?** *${botName} ${coreClient.commands.help.command}*`);
|
||||
}
|
||||
}
|
||||
else
|
||||
component.onTextMessage(message, guildData);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine details about a command invoked via a message
|
||||
* @param {*} message Discord.Message
|
||||
* @param {*[]} commands commands array (probably from commands.json)
|
||||
* @param {boolean} userIsAdmin whether the user is an admin
|
||||
*/
|
||||
function getCommandDetails(message, commands, userIsAdmin) {
|
||||
const splitMessage = message.content.toLowerCase().split(/ +/);
|
||||
const commandStr = splitMessage[1];
|
||||
|
@ -79,6 +86,12 @@ function getCommandDetails(message, commands, userIsAdmin) {
|
|||
return { command, commandProp, params: finalisedParams, expectedParamCount };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a help embed for available commands
|
||||
* @param {string} name name of the bot
|
||||
* @param {*[]} commands commands array
|
||||
* @param {boolean} userIsAdmin whether the user is admin
|
||||
*/
|
||||
function createHelpEmbed(name, commands, userIsAdmin) {
|
||||
const commandsArr = Object.keys(commands).map(x => commands[x]).filter(x => userIsAdmin || !x.admin);
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"discord.js": "11.2.0",
|
||||
"discordjs-util": "git+https://github.com/benji7425/discordjs-util.git",
|
||||
"jsonfile": "3.0.1",
|
||||
"parent-package-json": "2.0.1",
|
||||
"simple-file-writer": "2.0.0"
|
||||
|
|
Loading…
Reference in a new issue