V1.4.3 - Minor Update + Bugfixes
All files have received a handful of debug messages, this is to aid in finding the source of some recent crashes and to help find future issues config.example.ts, */index.html, README.md - version number bump utils.ts - Console will only get spammed by DEBUG level messages if artificer is in DEBUG mode. DEBUG statements are still logged to file solver.ts - actually set the original index on the rolls to allow drop/keep to reset the order correctly, change return text to use localPrefix and remove code blocks mod.ts - breaks args on \n now, -o arg now allows full words instead of just o or a, error checking on file size to make sure the results always send and details send when possible api.ts - added error checking on file size to make sure the results always send and details send when possible
This commit is contained in:
parent
d449d1d85d
commit
15864e7f6d
|
@ -1,5 +1,5 @@
|
||||||
# The Artificer - A Dice Rolling Discord Bot
|
# The Artificer - A Dice Rolling Discord Bot
|
||||||
Version 1.4.2 - 2021/02/14
|
Version 1.4.3 - 2021/03/21
|
||||||
|
|
||||||
The Artificer is a Discord bot that specializes in rolling dice. The bot utilizes the compact [Roll20 formatting](https://artificer.eanm.dev/roll20) for ease of use and will correctly perform any needed math on the roll (limited to basic algebra).
|
The Artificer is a Discord bot that specializes in rolling dice. The bot utilizes the compact [Roll20 formatting](https://artificer.eanm.dev/roll20) for ease of use and will correctly perform any needed math on the roll (limited to basic algebra).
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export const config = {
|
export const config = {
|
||||||
"name": "The Artificer", // Name of the bot
|
"name": "The Artificer", // Name of the bot
|
||||||
"version": "1.4.2", // Version of the bot
|
"version": "1.4.3", // Version of the bot
|
||||||
"token": "the_bot_token", // Discord API Token for this bot
|
"token": "the_bot_token", // Discord API Token for this bot
|
||||||
"localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token"
|
"localtoken": "local_testing_token", // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token"
|
||||||
"prefix": "[[", // Prefix for all commands
|
"prefix": "[[", // Prefix for all commands
|
||||||
|
|
40
mod.ts
40
mod.ts
|
@ -52,6 +52,7 @@ startBot({
|
||||||
|
|
||||||
// Interval to rotate the status text every 30 seconds to show off more commands
|
// Interval to rotate the status text every 30 seconds to show off more commands
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
utils.log(LT.LOG, "Changing bot status");
|
||||||
try {
|
try {
|
||||||
// Wrapped in try-catch due to hard crash possible
|
// Wrapped in try-catch due to hard crash possible
|
||||||
editBotsStatus(StatusTypes.Online, intervals.getRandomStatus(cache), ActivityType.Game);
|
editBotsStatus(StatusTypes.Online, intervals.getRandomStatus(cache), ActivityType.Game);
|
||||||
|
@ -61,7 +62,10 @@ startBot({
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
// Interval to update bot list stats every 24 hours
|
// Interval to update bot list stats every 24 hours
|
||||||
LOCALMODE ? utils.log(LT.INFO, "updateListStatistics not running") : setInterval(() => intervals.updateListStatistics(botID, cache.guilds.size), 86400000);
|
LOCALMODE ? utils.log(LT.INFO, "updateListStatistics not running") : setInterval(() => {
|
||||||
|
utils.log(LT.LOG, "Updating all bot lists statistics");
|
||||||
|
intervals.updateListStatistics(botID, cache.guilds.size);
|
||||||
|
}, 86400000);
|
||||||
|
|
||||||
// setTimeout added to make sure the startup message does not error out
|
// setTimeout added to make sure the startup message does not error out
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -73,11 +77,13 @@ startBot({
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
guildCreate: (guild: Guild) => {
|
guildCreate: (guild: Guild) => {
|
||||||
|
utils.log(LT.LOG, `Handling joining guild ${JSON.stringify(guild)}`);
|
||||||
sendMessage(config.logChannel, `New guild joined: ${guild.name} (id: ${guild.id}). This guild has ${guild.memberCount} members!`).catch(e => {
|
sendMessage(config.logChannel, `New guild joined: ${guild.name} (id: ${guild.id}). This guild has ${guild.memberCount} members!`).catch(e => {
|
||||||
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
guildDelete: (guild: Guild) => {
|
guildDelete: (guild: Guild) => {
|
||||||
|
utils.log(LT.LOG, `Handling leaving guild ${JSON.stringify(guild)}`);
|
||||||
sendMessage(config.logChannel, `I have been removed from: ${guild.name} (id: ${guild.id}).`).catch(e => {
|
sendMessage(config.logChannel, `I have been removed from: ${guild.name} (id: ${guild.id}).`).catch(e => {
|
||||||
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
utils.log(LT.ERROR, `Failed to send message: ${JSON.stringify(e)}`);
|
||||||
});
|
});
|
||||||
|
@ -90,8 +96,10 @@ startBot({
|
||||||
// Ignore all messages that are not commands
|
// Ignore all messages that are not commands
|
||||||
if (message.content.indexOf(config.prefix) !== 0) return;
|
if (message.content.indexOf(config.prefix) !== 0) return;
|
||||||
|
|
||||||
|
utils.log(LT.LOG, `Handling message ${JSON.stringify(message)}`);
|
||||||
|
|
||||||
// Split into standard command + args format
|
// Split into standard command + args format
|
||||||
const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
|
const args = message.content.slice(config.prefix.length).trim().split(/[ \n]+/g);
|
||||||
const command = args.shift()?.toLowerCase();
|
const command = args.shift()?.toLowerCase();
|
||||||
|
|
||||||
// All commands below here
|
// All commands below here
|
||||||
|
@ -126,7 +134,7 @@ startBot({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// [[rollhelp or [[rh or [[hr
|
// [[rollhelp or [[rh or [[hr or [[??
|
||||||
// Help command specifically for the roll command
|
// Help command specifically for the roll command
|
||||||
else if (command === "rollhelp" || command === "rh" || command === "hr" || command === "??" || command?.startsWith("xdy")) {
|
else if (command === "rollhelp" || command === "rh" || command === "hr" || command === "??" || command?.startsWith("xdy")) {
|
||||||
// Light telemetry to see how many times a command is being run
|
// Light telemetry to see how many times a command is being run
|
||||||
|
@ -384,6 +392,7 @@ startBot({
|
||||||
|
|
||||||
// Check if any of the args are command flags and pull those out into the modifiers object
|
// Check if any of the args are command flags and pull those out into the modifiers object
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Checking ${command + args.join(" ")} for command modifiers ${i}`);
|
||||||
switch (args[i].toLowerCase()) {
|
switch (args[i].toLowerCase()) {
|
||||||
case "-nd":
|
case "-nd":
|
||||||
modifiers.noDetails = true;
|
modifiers.noDetails = true;
|
||||||
|
@ -414,6 +423,7 @@ startBot({
|
||||||
|
|
||||||
// -gm is a little more complex, as we must get all of the GMs that need to be DMd
|
// -gm is a little more complex, as we must get all of the GMs that need to be DMd
|
||||||
while (((i + 1) < args.length) && args[i + 1].startsWith("<@")) {
|
while (((i + 1) < args.length) && args[i + 1].startsWith("<@")) {
|
||||||
|
utils.log(LT.LOG, `Finding all GMs, checking args ${JSON.stringify(args)}`);
|
||||||
// Keep looping thru the rest of the args until one does not start with the discord mention code
|
// Keep looping thru the rest of the args until one does not start with the discord mention code
|
||||||
modifiers.gms.push(args[i + 1].replace(/[!]/g, ""));
|
modifiers.gms.push(args[i + 1].replace(/[!]/g, ""));
|
||||||
args.splice((i + 1), 1);
|
args.splice((i + 1), 1);
|
||||||
|
@ -437,7 +447,7 @@ startBot({
|
||||||
case "-o":
|
case "-o":
|
||||||
args.splice(i, 1);
|
args.splice(i, 1);
|
||||||
|
|
||||||
if (args[i].toLowerCase() !== "d" && args[i].toLowerCase() !== "a") {
|
if (args[i].toLowerCase()[0] !== "d" && args[i].toLowerCase()[0] !== "a") {
|
||||||
// If -o is on and asc or desc was not specified, error out
|
// If -o is on and asc or desc was not specified, error out
|
||||||
m.edit("Error: Must specifiy a or d to order the rolls ascending or descending");
|
m.edit("Error: Must specifiy a or d to order the rolls ascending or descending");
|
||||||
|
|
||||||
|
@ -450,7 +460,7 @@ startBot({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiers.order = args[i].toLowerCase();
|
modifiers.order = args[i].toLowerCase()[0];
|
||||||
|
|
||||||
args.splice(i, 1);
|
args.splice(i, 1);
|
||||||
i--;
|
i--;
|
||||||
|
@ -509,9 +519,19 @@ startBot({
|
||||||
|
|
||||||
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
|
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
|
||||||
modifiers.gms.forEach(async e => {
|
modifiers.gms.forEach(async e => {
|
||||||
|
utils.log(LT.LOG, `Messaging GM ${e}`);
|
||||||
// If its too big, collapse it into a .txt file and send that instead.
|
// If its too big, collapse it into a .txt file and send that instead.
|
||||||
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
||||||
|
|
||||||
|
if (b.size > 8388290) {
|
||||||
|
// Update return text
|
||||||
|
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.";
|
||||||
|
|
||||||
|
// Attempt to DM the GMs and send a warning if it could not DM a GM
|
||||||
|
await sendDirectMessage(e.substr(2, (e.length - 3)), returnText).catch(() => {
|
||||||
|
utils.sendIndirectMessage(message, "WARNING: " + e + " could not be messaged. If this issue persists, make sure direct messages are allowed from this server.", sendMessage, sendDirectMessage);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
// Update return text
|
// Update return text
|
||||||
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details have been attached to this messaged as a `.txt` file for verification purposes.";
|
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details have been attached to this messaged as a `.txt` file for verification purposes.";
|
||||||
|
|
||||||
|
@ -519,6 +539,7 @@ startBot({
|
||||||
await sendDirectMessage(e.substr(2, (e.length - 3)), { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }).catch(() => {
|
await sendDirectMessage(e.substr(2, (e.length - 3)), { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }).catch(() => {
|
||||||
utils.sendIndirectMessage(message, "WARNING: " + e + " could not be messaged. If this issue persists, make sure direct messages are allowed from this server.", sendMessage, sendDirectMessage);
|
utils.sendIndirectMessage(message, "WARNING: " + e + " could not be messaged. If this issue persists, make sure direct messages are allowed from this server.", sendMessage, sendDirectMessage);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Finally send the text
|
// Finally send the text
|
||||||
|
@ -536,6 +557,13 @@ startBot({
|
||||||
// If its too big, collapse it into a .txt file and send that instead.
|
// If its too big, collapse it into a .txt file and send that instead.
|
||||||
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
||||||
|
|
||||||
|
if (b.size > 8388290) {
|
||||||
|
// Update return text
|
||||||
|
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.";
|
||||||
|
|
||||||
|
// Send the results
|
||||||
|
m.edit(returnText);
|
||||||
|
} else {
|
||||||
// Update return text
|
// Update return text
|
||||||
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a `.txt` file for verification purposes.";
|
returnText = "<@" + message.author.id + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a `.txt` file for verification purposes.";
|
||||||
|
|
||||||
|
@ -543,6 +571,7 @@ startBot({
|
||||||
m.delete();
|
m.delete();
|
||||||
|
|
||||||
await utils.sendIndirectMessage(message, { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }, sendMessage, sendDirectMessage);
|
await utils.sendIndirectMessage(message, { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }, sendMessage, sendDirectMessage);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Finally send the text
|
// Finally send the text
|
||||||
m.edit(returnText);
|
m.edit(returnText);
|
||||||
|
@ -565,6 +594,7 @@ startBot({
|
||||||
else {
|
else {
|
||||||
// Start looping thru the possible emojis
|
// Start looping thru the possible emojis
|
||||||
config.emojis.some((emoji: EmojiConf) => {
|
config.emojis.some((emoji: EmojiConf) => {
|
||||||
|
utils.log(LT.LOG, `Checking if command was emoji ${emoji}`);
|
||||||
// If a match gets found
|
// If a match gets found
|
||||||
if (emoji.aliases.indexOf(command || "") > -1) {
|
if (emoji.aliases.indexOf(command || "") > -1) {
|
||||||
// Light telemetry to see how many times a command is being run
|
// Light telemetry to see how many times a command is being run
|
||||||
|
|
32
src/api.ts
32
src/api.ts
|
@ -29,7 +29,7 @@ import config from "../config.ts";
|
||||||
// start initializes and runs the entire API for the bot
|
// start initializes and runs the entire API for the bot
|
||||||
const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string, m: (string | MessageContent)) => Promise<Message>, sendDirectMessage: (c: string, m: (string | MessageContent)) => Promise<Message>): Promise<void> => {
|
const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string, m: (string | MessageContent)) => Promise<Message>, sendDirectMessage: (c: string, m: (string | MessageContent)) => Promise<Message>): Promise<void> => {
|
||||||
const server = serve({ hostname: "0.0.0.0", port: config.api.port });
|
const server = serve({ hostname: "0.0.0.0", port: config.api.port });
|
||||||
utils.log(LT.LOG, `HTTP api running at: http://localhost:${config.api.port}/`);
|
utils.log(LT.INFO, `HTTP api running at: http://localhost:${config.api.port}/`);
|
||||||
|
|
||||||
// rateLimitTime holds all users with the last time they started a rate limit timer
|
// rateLimitTime holds all users with the last time they started a rate limit timer
|
||||||
const rateLimitTime = new Map<string, number>();
|
const rateLimitTime = new Map<string, number>();
|
||||||
|
@ -38,6 +38,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
|
||||||
|
|
||||||
// Catching every request made to the server
|
// Catching every request made to the server
|
||||||
for await (const request of server) {
|
for await (const request of server) {
|
||||||
|
utils.log(LT.LOG, `Handling request: ${JSON.stringify(request)}`);
|
||||||
// Check if user is authenticated to be using this API
|
// Check if user is authenticated to be using this API
|
||||||
let authenticated = false;
|
let authenticated = false;
|
||||||
let rateLimited = false;
|
let rateLimited = false;
|
||||||
|
@ -90,6 +91,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
|
||||||
const query = new Map<string, string>();
|
const query = new Map<string, string>();
|
||||||
if (tempQ !== undefined) {
|
if (tempQ !== undefined) {
|
||||||
tempQ.split("&").forEach(e => {
|
tempQ.split("&").forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Breaking down request query: ${request} ${e}`);
|
||||||
const [option, params] = e.split("=");
|
const [option, params] = e.split("=");
|
||||||
query.set(option.toLowerCase(), params);
|
query.set(option.toLowerCase(), params);
|
||||||
});
|
});
|
||||||
|
@ -279,6 +281,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
|
||||||
// Make a new return line to be sent to the roller
|
// Make a new return line to be sent to the roller
|
||||||
let normalText = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\nResults have been messaged to the following GMs: ";
|
let normalText = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\nResults have been messaged to the following GMs: ";
|
||||||
gms.forEach(e => {
|
gms.forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Appending GM ${e} to roll text`);
|
||||||
normalText += "<@" + e + "> ";
|
normalText += "<@" + e + "> ";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -295,16 +298,24 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
|
const newMessage: MessageContent = {};
|
||||||
gms.forEach(async e => {
|
|
||||||
// If its too big, collapse it into a .txt file and send that instead.
|
// If its too big, collapse it into a .txt file and send that instead.
|
||||||
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
||||||
|
|
||||||
|
if (b.size > 8388290) {
|
||||||
// Update return text
|
// Update return text
|
||||||
returnText = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details have been attached to this messaged as a `.txt` file for verification purposes.";
|
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.";
|
||||||
|
} else {
|
||||||
|
// Update return text
|
||||||
|
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nFull details have been attached to this messaged as a `.txt` file for verification purposes.";
|
||||||
|
newMessage.file = { "blob": b, "name": "rollDetails.txt" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// And message the full details to each of the GMs, alerting roller of every GM that could not be messaged
|
||||||
|
gms.forEach(async e => {
|
||||||
|
utils.log(LT.LOG, `Messaging GM ${e} roll results`);
|
||||||
// Attempt to DM the GMs and send a warning if it could not DM a GM
|
// Attempt to DM the GMs and send a warning if it could not DM a GM
|
||||||
await sendDirectMessage(e, { "content": returnText, "file": { "blob": b, "name": "rollDetails.txt" } }).catch(async () => {
|
await sendDirectMessage(e, newMessage).catch(async () => {
|
||||||
const failedSend = "WARNING: <@" + e + "> could not be messaged. If this issue persists, make sure direct messages are allowed from this server."
|
const failedSend = "WARNING: <@" + e + "> could not be messaged. If this issue persists, make sure direct messages are allowed from this server."
|
||||||
// Send the return message as a DM or normal message depening on if the channel is set
|
// Send the return message as a DM or normal message depening on if the channel is set
|
||||||
if ((query.get("channel") || "").length > 0) {
|
if ((query.get("channel") || "").length > 0) {
|
||||||
|
@ -342,13 +353,15 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
|
||||||
// If its too big, collapse it into a .txt file and send that instead.
|
// If its too big, collapse it into a .txt file and send that instead.
|
||||||
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
const b = await new Blob([returnText as BlobPart], { "type": "text" });
|
||||||
|
|
||||||
|
if (b.size > 8388290) {
|
||||||
// Update return text
|
// Update return text
|
||||||
returnText = "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a `.txt` file for verification purposes.";
|
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details could not be attached to this messaged as a `.txt` file as the file would be too large for Discord to handle. If you would like to see the details of rolls, please send the rolls in multiple messages instead of bundled into one.";
|
||||||
|
} else {
|
||||||
// Set info into the newMessage
|
// Update return text
|
||||||
newMessage.content = returnText;
|
newMessage.content = apiPrefix + "<@" + query.get("user") + ">" + returnmsg.line1 + "\n" + returnmsg.line2 + "\nDetails have been ommitted from this message for being over 2000 characters. Full details have been attached to this messaged as a `.txt` file for verification purposes.";
|
||||||
newMessage.file = { "blob": b, "name": "rollDetails.txt" };
|
newMessage.file = { "blob": b, "name": "rollDetails.txt" };
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Send the return message as a DM or normal message depening on if the channel is set
|
// Send the return message as a DM or normal message depening on if the channel is set
|
||||||
if ((query.get("channel") || "").length > 0) {
|
if ((query.get("channel") || "").length > 0) {
|
||||||
|
@ -672,6 +685,7 @@ const start = async (dbClient: Client, cache: CacheData, sendMessage: (c: string
|
||||||
const query = new Map<string, string>();
|
const query = new Map<string, string>();
|
||||||
if (tempQ !== undefined) {
|
if (tempQ !== undefined) {
|
||||||
tempQ.split("&").forEach(e => {
|
tempQ.split("&").forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Parsing request query #2 ${request} ${e}`);
|
||||||
const [option, params] = e.split("=");
|
const [option, params] = e.split("=");
|
||||||
query.set(option.toLowerCase(), params);
|
query.set(option.toLowerCase(), params);
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,6 +39,7 @@ const getRandomStatus = (cache: CacheData): string => {
|
||||||
// Sends the current server count to all bot list sites we are listed on
|
// Sends the current server count to all bot list sites we are listed on
|
||||||
const updateListStatistics = (botID: string, serverCount: number): void => {
|
const updateListStatistics = (botID: string, serverCount: number): void => {
|
||||||
config.botLists.forEach(async e => {
|
config.botLists.forEach(async e => {
|
||||||
|
utils.log(LT.LOG, `Updating statistics for ${JSON.stringify(e)}`)
|
||||||
if (e.enabled) {
|
if (e.enabled) {
|
||||||
const tempHeaders = new Headers();
|
const tempHeaders = new Headers();
|
||||||
tempHeaders.append(e.headers[0].header, e.headers[0].value);
|
tempHeaders.append(e.headers[0].header, e.headers[0].value);
|
||||||
|
@ -49,7 +50,7 @@ const updateListStatistics = (botID: string, serverCount: number): void => {
|
||||||
"headers": tempHeaders,
|
"headers": tempHeaders,
|
||||||
"body": JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()) // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number
|
"body": JSON.stringify(e.body).replace('"?{server_count}"', serverCount.toString()) // ?{server_count} needs the "" removed from around it aswell to make sure its sent as a number
|
||||||
});
|
});
|
||||||
utils.log(LT.LOG, `${JSON.stringify(response)}`);
|
utils.log(LT.INFO, `Posted server count to ${e.name}. Results: ${JSON.stringify(response)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,6 +61,7 @@ const compareOrigidx = (a: RollSet, b: RollSet): number => {
|
||||||
const escapeCharacters = (str: string, esc: string): string => {
|
const escapeCharacters = (str: string, esc: string): string => {
|
||||||
// Loop thru each esc char one at a time
|
// Loop thru each esc char one at a time
|
||||||
for (let i = 0; i < esc.length; i++) {
|
for (let i = 0; i < esc.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Escaping character ${esc[i]} | ${str}, ${esc}`);
|
||||||
// Create a new regex to look for that char that needs replaced and escape it
|
// Create a new regex to look for that char that needs replaced and escape it
|
||||||
const temprgx = new RegExp(`[${esc[i]}]`, "g");
|
const temprgx = new RegExp(`[${esc[i]}]`, "g");
|
||||||
str = str.replace(temprgx, ("\\" + esc[i]));
|
str = str.replace(temprgx, ("\\" + esc[i]));
|
||||||
|
@ -162,6 +163,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
|
|
||||||
// Loop until all remaining args are parsed
|
// Loop until all remaining args are parsed
|
||||||
while (remains.length > 0) {
|
while (remains.length > 0) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Parsing remains ${remains}`);
|
||||||
// Find the next number in the remains to be able to cut out the rule name
|
// Find the next number in the remains to be able to cut out the rule name
|
||||||
let afterSepIdx = remains.search(/\d/);
|
let afterSepIdx = remains.search(/\d/);
|
||||||
if (afterSepIdx < 0) {
|
if (afterSepIdx < 0) {
|
||||||
|
@ -217,6 +219,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Parsing cs> ${i}`);
|
||||||
rollConf.critScore.range.push(i);
|
rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -224,6 +227,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritScore for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critScore.on = true;
|
rollConf.critScore.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Parsing cs< ${i}`);
|
||||||
rollConf.critScore.range.push(i);
|
rollConf.critScore.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -237,6 +241,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers greater than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
for (let i = tNum; i <= rollConf.dieSize; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Parsing cf> ${i}`);
|
||||||
rollConf.critFail.range.push(i);
|
rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -244,6 +249,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
// Configure CritFail for all numbers less than or equal to tNum (this could happen multiple times, but why)
|
||||||
rollConf.critFail.on = true;
|
rollConf.critFail.on = true;
|
||||||
for (let i = 0; i <= tNum; i++) {
|
for (let i = 0; i <= tNum; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Parsing cf< ${i}`);
|
||||||
rollConf.critFail.range.push(i);
|
rollConf.critFail.range.push(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -271,6 +277,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
// Since only one drop or keep option can be active, count how many are active to throw the right error
|
||||||
let dkdkCnt = 0;
|
let dkdkCnt = 0;
|
||||||
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach(e => {
|
[rollConf.drop.on, rollConf.keep.on, rollConf.dropHigh.on, rollConf.keepLow.on].forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Checking if drop/keep is on ${e}`);
|
||||||
if (e) {
|
if (e) {
|
||||||
dkdkCnt++;
|
dkdkCnt++;
|
||||||
}
|
}
|
||||||
|
@ -335,6 +342,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
|
|
||||||
// Initial rolling, not handling reroll or exploding here
|
// Initial rolling, not handling reroll or exploding here
|
||||||
for (let i = 0; i < rollConf.dieCount; i++) {
|
for (let i = 0; i < rollConf.dieCount; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Initial rolling ${i} of ${JSON.stringify(rollConf)}`);
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > MAXLOOPS) {
|
||||||
throw new Error("MaxLoopsExceeded");
|
throw new Error("MaxLoopsExceeded");
|
||||||
|
@ -344,6 +352,8 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
const rolling = JSON.parse(JSON.stringify(templateRoll));
|
const rolling = JSON.parse(JSON.stringify(templateRoll));
|
||||||
// If maximiseRoll is on, set the roll to the dieSize, else if nominalRoll is on, set the roll to the average roll of dieSize, else generate a new random roll
|
// If maximiseRoll is on, set the roll to the dieSize, else if nominalRoll is on, set the roll to the average roll of dieSize, else generate a new random roll
|
||||||
rolling.roll = maximiseRoll ? rollConf.dieSize : (nominalRoll ? ((rollConf.dieSize / 2) + 0.5) : genRoll(rollConf.dieSize));
|
rolling.roll = maximiseRoll ? rollConf.dieSize : (nominalRoll ? ((rollConf.dieSize / 2) + 0.5) : genRoll(rollConf.dieSize));
|
||||||
|
// Set origidx of roll
|
||||||
|
rolling.origidx = i;
|
||||||
|
|
||||||
// If critScore arg is on, check if the roll should be a crit, if its off, check if the roll matches the die size
|
// If critScore arg is on, check if the roll should be a crit, if its off, check if the roll matches the die size
|
||||||
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(rolling.roll) >= 0) {
|
if (rollConf.critScore.on && rollConf.critScore.range.indexOf(rolling.roll) >= 0) {
|
||||||
|
@ -366,6 +376,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// If needed, handle rerolling and exploding dice now
|
// If needed, handle rerolling and exploding dice now
|
||||||
if (rollConf.reroll.on || rollConf.exploding) {
|
if (rollConf.reroll.on || rollConf.exploding) {
|
||||||
for (let i = 0; i < rollSet.length; i++) {
|
for (let i = 0; i < rollSet.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Handling rerolling and exploding ${JSON.stringify(rollSet[i])}`);
|
||||||
// If loopCount gets too high, stop trying to calculate infinity
|
// If loopCount gets too high, stop trying to calculate infinity
|
||||||
if (loopCount > MAXLOOPS) {
|
if (loopCount > MAXLOOPS) {
|
||||||
throw new Error("MaxLoopsExceeded");
|
throw new Error("MaxLoopsExceeded");
|
||||||
|
@ -432,6 +443,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
let rerollCount = 0;
|
let rerollCount = 0;
|
||||||
if (rollConf.reroll.on) {
|
if (rollConf.reroll.on) {
|
||||||
for (let i = 0; i < rollSet.length; i++) {
|
for (let i = 0; i < rollSet.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Setting originalIdx on ${JSON.stringify(rollSet[i])}`);
|
||||||
rollSet[i].origidx = i;
|
rollSet[i].origidx = i;
|
||||||
|
|
||||||
if (rollSet[i].rerolled) {
|
if (rollSet[i].rerolled) {
|
||||||
|
@ -480,6 +492,7 @@ const roll = (rollStr: string, maximiseRoll: boolean, nominalRoll: boolean): Rol
|
||||||
// Now its time to drop all dice needed
|
// Now its time to drop all dice needed
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (dropCount > 0 && i < rollSet.length) {
|
while (dropCount > 0 && i < rollSet.length) {
|
||||||
|
utils.log(LT.LOG, `Handling roll ${rollStr} | Dropping dice ${dropCount} ${JSON.stringify(rollSet[i])}`);
|
||||||
// Skip all rolls that were rerolled
|
// Skip all rolls that were rerolled
|
||||||
if (!rollSet[i].rerolled) {
|
if (!rollSet[i].rerolled) {
|
||||||
rollSet[i].dropped = true;
|
rollSet[i].dropped = true;
|
||||||
|
@ -508,6 +521,7 @@ const formatRoll = (rollConf: string, maximiseRoll: boolean, nominalRoll: boolea
|
||||||
|
|
||||||
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
// Loop thru all parts of the roll to document everything that was done to create the total roll
|
||||||
tempRollSet.forEach(e => {
|
tempRollSet.forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Formatting roll ${rollConf} | ${JSON.stringify(e)}`);
|
||||||
let preFormat = "";
|
let preFormat = "";
|
||||||
let postFormat = "";
|
let postFormat = "";
|
||||||
|
|
||||||
|
@ -573,6 +587,7 @@ const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean
|
||||||
|
|
||||||
// Evaluate all parenthesis
|
// Evaluate all parenthesis
|
||||||
while (conf.indexOf("(") > -1) {
|
while (conf.indexOf("(") > -1) {
|
||||||
|
utils.log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for (`);
|
||||||
// Get first open parenthesis
|
// Get first open parenthesis
|
||||||
const openParen = conf.indexOf("(");
|
const openParen = conf.indexOf("(");
|
||||||
let closeParen = -1;
|
let closeParen = -1;
|
||||||
|
@ -580,6 +595,7 @@ const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean
|
||||||
|
|
||||||
// Using nextParen to count the opening/closing parens, find the matching paren to openParen above
|
// Using nextParen to count the opening/closing parens, find the matching paren to openParen above
|
||||||
for (let i = openParen; i < conf.length; i++) {
|
for (let i = openParen; i < conf.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Looking for matching ) openIdx: ${openParen} checking: ${i}`);
|
||||||
// If we hit an open, add one (this includes the openParen we start with), if we hit a close, subtract one
|
// If we hit an open, add one (this includes the openParen we start with), if we hit a close, subtract one
|
||||||
if (conf[i] === "(") {
|
if (conf[i] === "(") {
|
||||||
nextParen++;
|
nextParen++;
|
||||||
|
@ -622,8 +638,10 @@ const fullSolver = (conf: (string | number | SolvedStep)[], wrapDetails: boolean
|
||||||
// Evaluate all EMMDAS by looping thru each teir of operators (exponential is the higehest teir, addition/subtraction the lowest)
|
// Evaluate all EMMDAS by looping thru each teir of operators (exponential is the higehest teir, addition/subtraction the lowest)
|
||||||
const allCurOps = [["^"], ["*", "/", "%"], ["+", "-"]];
|
const allCurOps = [["^"], ["*", "/", "%"], ["+", "-"]];
|
||||||
allCurOps.forEach(curOps => {
|
allCurOps.forEach(curOps => {
|
||||||
|
utils.log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)}`);
|
||||||
// Iterate thru all operators/operands in the conf
|
// Iterate thru all operators/operands in the conf
|
||||||
for (let i = 0; i < conf.length; i++) {
|
for (let i = 0; i < conf.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Evaluating roll ${JSON.stringify(conf)} | Evaluating ${JSON.stringify(curOps)} | Checking ${JSON.stringify(conf[i])}`);
|
||||||
// Check if the current index is in the active teir of operators
|
// Check if the current index is in the active teir of operators
|
||||||
if (curOps.indexOf(conf[i].toString()) > -1) {
|
if (curOps.indexOf(conf[i].toString()) > -1) {
|
||||||
// Grab the operands from before and after the operator
|
// Grab the operands from before and after the operator
|
||||||
|
@ -754,6 +772,7 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
|
||||||
|
|
||||||
// Loop thru all roll/math ops
|
// Loop thru all roll/math ops
|
||||||
for (let i = 0; i < sepRolls.length; i++) {
|
for (let i = 0; i < sepRolls.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Parsing roll ${fullCmd} | Working ${sepRolls[i]}`);
|
||||||
// Split the current iteration on the command postfix to separate the operation to be parsed and the text formatting after the opertaion
|
// Split the current iteration on the command postfix to separate the operation to be parsed and the text formatting after the opertaion
|
||||||
const [tempConf, tempFormat] = sepRolls[i].split(localPostfix);
|
const [tempConf, tempFormat] = sepRolls[i].split(localPostfix);
|
||||||
|
|
||||||
|
@ -763,6 +782,7 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
|
||||||
// Verify there are equal numbers of opening and closing parenthesis by adding 1 for opening parens and subtracting 1 for closing parens
|
// Verify there are equal numbers of opening and closing parenthesis by adding 1 for opening parens and subtracting 1 for closing parens
|
||||||
let parenCnt = 0;
|
let parenCnt = 0;
|
||||||
mathConf.forEach(e => {
|
mathConf.forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Parsing roll ${fullCmd} | Checking parenthesis balance ${e}`);
|
||||||
if (e === "(") {
|
if (e === "(") {
|
||||||
parenCnt++;
|
parenCnt++;
|
||||||
} else if (e === ")") {
|
} else if (e === ")") {
|
||||||
|
@ -777,6 +797,7 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
|
||||||
|
|
||||||
// Evaluate all rolls into stepSolve format and all numbers into floats
|
// Evaluate all rolls into stepSolve format and all numbers into floats
|
||||||
for (let i = 0; i < mathConf.length; i++) {
|
for (let i = 0; i < mathConf.length; i++) {
|
||||||
|
utils.log(LT.LOG, `Parsing roll ${fullCmd} | Evaluating rolls into mathable items ${JSON.stringify(mathConf[i])}`);
|
||||||
if (mathConf[i].toString().length === 0) {
|
if (mathConf[i].toString().length === 0) {
|
||||||
// If its an empty string, get it out of here
|
// If its an empty string, get it out of here
|
||||||
mathConf.splice(i, 1);
|
mathConf.splice(i, 1);
|
||||||
|
@ -841,8 +862,9 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
|
||||||
fullCmd = fullCmd.substr(0, (fullCmd.length - 1));
|
fullCmd = fullCmd.substr(0, (fullCmd.length - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape any | chars in fullCmd to prevent spoilers from acting up
|
// Escape any | and ` chars in fullCmd to prevent spoilers and code blocks from acting up
|
||||||
fullCmd = escapeCharacters(fullCmd, "|");
|
fullCmd = escapeCharacters(fullCmd, "|");
|
||||||
|
fullCmd = fullCmd.replace(/`/g, "");
|
||||||
|
|
||||||
let line1 = "";
|
let line1 = "";
|
||||||
let line2 = "";
|
let line2 = "";
|
||||||
|
@ -850,27 +872,28 @@ const parseRoll = (fullCmd: string, localPrefix: string, localPostfix: string, m
|
||||||
|
|
||||||
// If maximiseRoll or nominalRoll are on, mark the output as such, else use default formatting
|
// If maximiseRoll or nominalRoll are on, mark the output as such, else use default formatting
|
||||||
if (maximiseRoll) {
|
if (maximiseRoll) {
|
||||||
line1 = " requested the theoretical maximum of: `[[" + fullCmd + "`";
|
line1 = ` requested the theoretical maximum of: \`${localPrefix}${fullCmd}\``;
|
||||||
line2 = "Theoretical Maximum Results: ";
|
line2 = "Theoretical Maximum Results: ";
|
||||||
} else if (nominalRoll) {
|
} else if (nominalRoll) {
|
||||||
line1 = " requested the theoretical nominal of: `[[" + fullCmd + "`";
|
line1 = ` requested the theoretical nominal of: \`${localPrefix}${fullCmd}\``;
|
||||||
line2 = "Theoretical Nominal Results: ";
|
line2 = "Theoretical Nominal Results: ";
|
||||||
} else if (order === "a") {
|
} else if (order === "a") {
|
||||||
line1 = " requested the following rolls to be ordered from least to greatest: `[[" + fullCmd + "`";
|
line1 = ` requested the following rolls to be ordered from least to greatest: \`${localPrefix}${fullCmd}\``;
|
||||||
line2 = "Results: ";
|
line2 = "Results: ";
|
||||||
tempReturnData.sort(compareTotalRolls);
|
tempReturnData.sort(compareTotalRolls);
|
||||||
} else if (order === "d") {
|
} else if (order === "d") {
|
||||||
line1 = " requested the following rolls to be ordered from greatest to least: `[[" + fullCmd + "`";
|
line1 = ` requested the following rolls to be ordered from greatest to least: \`${localPrefix}${fullCmd}\``;
|
||||||
line2 = "Results: ";
|
line2 = "Results: ";
|
||||||
tempReturnData.sort(compareTotalRolls);
|
tempReturnData.sort(compareTotalRolls);
|
||||||
tempReturnData.reverse();
|
tempReturnData.reverse();
|
||||||
} else {
|
} else {
|
||||||
line1 = " rolled: `[[" + fullCmd + "`";
|
line1 = ` rolled: \`${localPrefix}${fullCmd}\``;
|
||||||
line2 = "Results: ";
|
line2 = "Results: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out all of the details and results now
|
// Fill out all of the details and results now
|
||||||
tempReturnData.forEach(e => {
|
tempReturnData.forEach(e => {
|
||||||
|
utils.log(LT.LOG, `Parsing roll ${fullCmd} | Making return text ${JSON.stringify(e)}`);
|
||||||
let preFormat = "";
|
let preFormat = "";
|
||||||
let postFormat = "";
|
let postFormat = "";
|
||||||
|
|
||||||
|
|
50
src/utils.ts
50
src/utils.ts
|
@ -12,6 +12,7 @@ import {
|
||||||
nanoid
|
nanoid
|
||||||
} from "../deps.ts";
|
} from "../deps.ts";
|
||||||
|
|
||||||
|
import { DEBUG } from "../flags.ts";
|
||||||
import { LogTypes } from "./utils.enums.ts";
|
import { LogTypes } from "./utils.enums.ts";
|
||||||
|
|
||||||
// Constant initialized at runtime for consistent file names
|
// Constant initialized at runtime for consistent file names
|
||||||
|
@ -19,36 +20,6 @@ let startDate: string;
|
||||||
let logFolder: string;
|
let logFolder: string;
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
|
|
||||||
// split2k(longMessage) returns shortMessage[]
|
|
||||||
// split2k takes a long string in and cuts it into shorter strings to be sent in Discord
|
|
||||||
const split2k = (chunk: string): string[] => {
|
|
||||||
// Replace any malformed newline characters
|
|
||||||
chunk = chunk.replace(/\\n/g, "\n");
|
|
||||||
const bites = [];
|
|
||||||
|
|
||||||
// While there is more characters than allowed to be sent in discord
|
|
||||||
while (chunk.length > 2000) {
|
|
||||||
// Take 2001 chars to see if word magically ends on char 2000
|
|
||||||
let bite = chunk.substr(0, 2001);
|
|
||||||
const lastI = bite.lastIndexOf(" ");
|
|
||||||
if (lastI < 2000) {
|
|
||||||
// If there is a final word before the 2000 split point, split right after that word
|
|
||||||
bite = bite.substr(0, lastI);
|
|
||||||
} else {
|
|
||||||
// Else cut exactly 2000 characters
|
|
||||||
bite = bite.substr(0, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push and remove the bite taken out of the chunk
|
|
||||||
bites.push(bite);
|
|
||||||
chunk = chunk.slice(bite.length);
|
|
||||||
}
|
|
||||||
// Push leftovers into bites
|
|
||||||
bites.push(chunk);
|
|
||||||
|
|
||||||
return bites;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ask(prompt) returns string
|
// ask(prompt) returns string
|
||||||
// ask prompts the user at command line for message
|
// ask prompts the user at command line for message
|
||||||
const ask = async (question: string, stdin = Deno.stdin, stdout = Deno.stdout): Promise<string> => {
|
const ask = async (question: string, stdin = Deno.stdin, stdout = Deno.stdout): Promise<string> => {
|
||||||
|
@ -101,14 +72,10 @@ const cmdPrompt = async (logChannel: string, botName: string, sendMessage: (c: s
|
||||||
const channelID = args.shift() || "";
|
const channelID = args.shift() || "";
|
||||||
const message = args.join(" ");
|
const message = args.join(" ");
|
||||||
|
|
||||||
// Utilize the split2k function to ensure a message over 2000 chars is not sent
|
sendMessage(channelID, message).catch(reason => {
|
||||||
const messages = split2k(message);
|
|
||||||
for (let i = 0; i < messages.length; i++) {
|
|
||||||
sendMessage(channelID, messages[i]).catch(reason => {
|
|
||||||
console.error(reason);
|
console.error(reason);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -119,14 +86,10 @@ const cmdPrompt = async (logChannel: string, botName: string, sendMessage: (c: s
|
||||||
else if (command === "ml") {
|
else if (command === "ml") {
|
||||||
const message = args.join(" ");
|
const message = args.join(" ");
|
||||||
|
|
||||||
// Utilize the split2k function to ensure a message over 2000 chars is not sent
|
sendMessage(logChannel, message).catch(reason => {
|
||||||
const messages = split2k(message);
|
|
||||||
for (let i = 0; i < messages.length; i++) {
|
|
||||||
sendMessage(logChannel, messages[i]).catch(reason => {
|
|
||||||
console.error(reason);
|
console.error(reason);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// help or h
|
// help or h
|
||||||
// Shows a basic help menu
|
// Shows a basic help menu
|
||||||
|
@ -183,10 +146,13 @@ const initLog = (name: string): void => {
|
||||||
// Handles sending messages to console.log and sending a copy of the log to a file for review on crashes
|
// Handles sending messages to console.log and sending a copy of the log to a file for review on crashes
|
||||||
const log = async (level: LogTypes, message: string, error = new Error()): Promise<void> => {
|
const log = async (level: LogTypes, message: string, error = new Error()): Promise<void> => {
|
||||||
const msgId = await nanoid(10);
|
const msgId = await nanoid(10);
|
||||||
const formattedMsg = `${new Date().toISOString()} | ${msgId} | ${level} | ${message}`;
|
const formattedMsg = `${new Date().toISOString()} | ${msgId} | ${level.padEnd(5)} | ${message}`;
|
||||||
const traceMsg = `${error.stack}`
|
const traceMsg = `${error.stack}`
|
||||||
// Default functionality of logging to console
|
// Default functionality of logging to console
|
||||||
|
if (level !== LogTypes.LOG || DEBUG) {
|
||||||
console[level](formattedMsg);
|
console[level](formattedMsg);
|
||||||
|
}
|
||||||
|
|
||||||
// Logging to files for permanent info
|
// Logging to files for permanent info
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
await Deno.writeTextFile(`./${logFolder}/${level}/${startDate}.log`, `${formattedMsg}\n`, {append: true});
|
await Deno.writeTextFile(`./${logFolder}/${level}/${startDate}.log`, `${formattedMsg}\n`, {append: true});
|
||||||
|
@ -195,4 +161,4 @@ const log = async (level: LogTypes, message: string, error = new Error()): Promi
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default { split2k, cmdPrompt, sendIndirectMessage, initLog, log };
|
export default { cmdPrompt, sendIndirectMessage, initLog, log };
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
Built by <a href="https://github.com/Burn-E99/" target="_blank">Ean Milligan</a>
|
Built by <a href="https://github.com/Burn-E99/" target="_blank">Ean Milligan</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer-right">
|
<div id="footer-right">
|
||||||
Version 1.4.2
|
Version 1.4.3
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
Built by <a href="https://github.com/Burn-E99/" target="_blank">Ean Milligan</a>
|
Built by <a href="https://github.com/Burn-E99/" target="_blank">Ean Milligan</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer-right">
|
<div id="footer-right">
|
||||||
Version 1.4.2
|
Version 1.4.3
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue