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:
benji7425 2017-09-19 23:26:30 +01:00
parent 0601c29c85
commit 2b0750dada
7 changed files with 166 additions and 117 deletions

View File

@ -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

View File

@ -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
View 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;

View File

@ -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,

View File

@ -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);

View File

@ -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"