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]
|
[subrepo]
|
||||||
remote = git@github.com:benji7425/discord-bot-core.git
|
remote = git@github.com:benji7425/discord-bot-core.git
|
||||||
branch = master
|
branch = master
|
||||||
commit = c4f07d0a8d4585083c3f167c1dce55cbeeda05d2
|
commit = 8e6d6ce99e581f5ac5fb899112ef33bcf3e16a34
|
||||||
parent = 341964a90ddca9afc684fd9331fc4177b8b68c04
|
parent = 341964a90ddca9afc684fd9331fc4177b8b68c04
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.3.1
|
cmdver = 0.3.1
|
||||||
|
|
|
@ -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;
|
|
|
@ -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 = {
|
module.exports = {
|
||||||
bootstrap: require("./bootstrapper.js"),
|
Client: require("./client.js"),
|
||||||
util: require("./util.js"),
|
util: require("./util.js"),
|
||||||
details: {
|
details: {
|
||||||
website: Config.website,
|
website: Config.website,
|
||||||
|
|
|
@ -4,60 +4,67 @@ const Util = require("util");
|
||||||
//external lib imports
|
//external lib imports
|
||||||
const Discord = require("discord.js");
|
const Discord = require("discord.js");
|
||||||
|
|
||||||
//lib components
|
//component imports
|
||||||
const Config = require("./config.json"); //generic lib configuration
|
const Config = require("./internal-config.json"); //generic lib configuration
|
||||||
const DiscordUtil = require("./util.js"); //some discordjs helper functions of mine
|
|
||||||
const ParentPackageJSON = require("../package.json"); //used to provide some info about the bot
|
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)
|
if (!guildData)
|
||||||
guildData = guildsData[message.guild.id] = new guildDataModel({ id: message.guild.id });
|
guildData = guildsData[message.guild.id] = new coreClient.guildDataModel({ id: message.guild.id });
|
||||||
|
|
||||||
if (isCommand) {
|
if (!isCommand)
|
||||||
Object.assign(commands, Config.commands);
|
return coreClient.implementations.onTextMessage(message, guildData).then(msg => resolve(msg));
|
||||||
|
|
||||||
|
Object.assign(coreClient.commands, Config.commands);
|
||||||
const userIsAdmin = message.member.permissions.has("ADMINISTRATOR");
|
const userIsAdmin = message.member.permissions.has("ADMINISTRATOR");
|
||||||
const botName = "@" + (message.guild.me.nickname || client.user.username);
|
const botName = "@" + (message.guild.me.nickname || coreClient.actual.user.username);
|
||||||
const { command, commandProp, params, expectedParamCount } = getCommandDetails(message, commands, userIsAdmin) || { command: null, commandProp: null, params: null, expectedParamCount: null };
|
const { command, commandProp, params, expectedParamCount } = getCommandDetails(message, coreClient.commands, userIsAdmin) || { command: null, commandProp: null, params: null, expectedParamCount: null };
|
||||||
const invoke = component[commandProp];
|
const invoke = coreClient.implementations[commandProp];
|
||||||
|
|
||||||
if (!command || !params || isNaN(expectedParamCount))
|
if (!command || !params || isNaN(expectedParamCount))
|
||||||
return;
|
return reject(`'${message.content.split(" ")[1]}' is not a recognised command`);
|
||||||
|
|
||||||
switch (command) {
|
if (command === Config.commands.version)
|
||||||
case Config.commands.version:
|
resolve(`${ParentPackageJSON.name} v${ParentPackageJSON.version}`);
|
||||||
message.reply(`${ParentPackageJSON.name} v${ParentPackageJSON.version}`);
|
else if (command === Config.commands.help)
|
||||||
break;
|
message.channel.send(createHelpEmbed(botName, coreClient.commands, userIsAdmin));
|
||||||
case Config.commands.help:
|
else {
|
||||||
message.channel.send(createHelpEmbed(botName, commands, userIsAdmin));
|
if (invoke && params.length >= expectedParamCount)
|
||||||
break;
|
invoke({ command, params: params, guildData, botName, message, coreClient })
|
||||||
default:
|
.then(msg =>
|
||||||
if (invoke && params.length >= expectedParamCount) {
|
resolve(msg))
|
||||||
invoke({ params, guildData, botName, message, client })
|
.catch(err => reject(err));
|
||||||
.then(msg => {
|
else
|
||||||
message.reply(msg);
|
reject(`Incorrect syntax!\n**Expected:** *${botName} ${command.syntax}*\n**Need help?** *${botName} ${coreClient.commands.help.command}*`);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
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) {
|
function getCommandDetails(message, commands, userIsAdmin) {
|
||||||
const splitMessage = message.content.toLowerCase().split(/ +/);
|
const splitMessage = message.content.toLowerCase().split(/ +/);
|
||||||
const commandStr = splitMessage[1];
|
const commandStr = splitMessage[1];
|
||||||
|
@ -79,6 +86,12 @@ function getCommandDetails(message, commands, userIsAdmin) {
|
||||||
return { command, commandProp, params: finalisedParams, expectedParamCount };
|
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) {
|
function createHelpEmbed(name, commands, userIsAdmin) {
|
||||||
const commandsArr = Object.keys(commands).map(x => commands[x]).filter(x => userIsAdmin || !x.admin);
|
const commandsArr = Object.keys(commands).map(x => commands[x]).filter(x => userIsAdmin || !x.admin);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "11.2.0",
|
"discord.js": "11.2.0",
|
||||||
"discordjs-util": "git+https://github.com/benji7425/discordjs-util.git",
|
|
||||||
"jsonfile": "3.0.1",
|
"jsonfile": "3.0.1",
|
||||||
"parent-package-json": "2.0.1",
|
"parent-package-json": "2.0.1",
|
||||||
"simple-file-writer": "2.0.0"
|
"simple-file-writer": "2.0.0"
|
||||||
|
|
Loading…
Reference in New Issue