aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commands/dev/eval.ts45
-rw-r--r--src/commands/utilities/decode.ts36
-rw-r--r--src/commands/utilities/price.ts124
-rw-r--r--src/inhibitors/noCache.ts4
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts4
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts49
-rw-r--r--src/lib/extensions/global.d.ts3
7 files changed, 113 insertions, 152 deletions
diff --git a/src/commands/dev/eval.ts b/src/commands/dev/eval.ts
index af6219b..ecac5f0 100644
--- a/src/commands/dev/eval.ts
+++ b/src/commands/dev/eval.ts
@@ -1,39 +1,8 @@
import { BushCommand, BushMessage, BushSlashMessage } from '@lib';
import { exec } from 'child_process';
-import { MessageEmbed as _MessageEmbed, Util } from 'discord.js';
+import { MessageEmbed as _MessageEmbed } from 'discord.js';
import { transpile } from 'typescript';
-import { inspect, InspectOptions, promisify } from 'util';
-
-const mapCredential = (old: string) => {
- const mapping = {
- ['token']: 'Main Token',
- ['devToken']: 'Dev Token',
- ['betaToken']: 'Beta Token',
- ['hypixelApiKey']: 'Hypixel Api Key'
- };
- return mapping[old] || old;
-};
-const redact = (text: string) => {
- for (const credentialName in client.config.credentials) {
- const credential = client.config.credentials[credentialName];
- const replacement = mapCredential(credentialName);
- const escapeRegex = /[.*+?^${}()|[\]\\]/g;
- text = text.replace(new RegExp(credential.toString().replace(escapeRegex, '\\$&'), 'g'), `[${replacement} Omitted]`);
- text = text.replace(
- new RegExp([...credential.toString()].reverse().join('').replace(escapeRegex, '\\$&'), 'g'),
- `[${replacement} Omitted]`
- );
- }
- return text;
-};
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-const inspectCleanRedactCodeblock = async (input: any, language: 'ts' | 'js', inspectOptions?: InspectOptions) => {
- input = typeof input !== 'string' && inspectOptions !== undefined ? inspect(input, inspectOptions) : input;
- input = Util.cleanCodeBlockContent(input);
- input = redact(input);
- return client.util.codeblock(input, 1024, language);
-};
+import { promisify } from 'util';
export default class EvalCommand extends BushCommand {
public constructor() {
@@ -142,18 +111,18 @@ export default class EvalCommand extends BushCommand {
{ Canvas } = await import('node-canvas');
/* eslint-enable @typescript-eslint/no-unused-vars */
- const inputJS = await inspectCleanRedactCodeblock(code.js, 'js');
- const inputTS = code.lang === 'ts' ? await inspectCleanRedactCodeblock(code.ts, 'ts') : undefined;
+ const inputJS = await util.inspectCleanRedactCodeblock(code.js, 'js');
+ const inputTS = code.lang === 'ts' ? await util.inspectCleanRedactCodeblock(code.ts, 'ts') : undefined;
try {
const rawOutput = code[code.lang].replace(/ /g, '').includes('9+10' || '10+9') ? '21' : await eval(code.js);
- const output = await inspectCleanRedactCodeblock(rawOutput, 'js', {
+ const output = await util.inspectCleanRedactCodeblock(rawOutput, 'js', {
depth: args.sel_depth || 0,
showHidden: args.hidden,
getters: true,
showProxy: true
});
const proto = args.show_proto
- ? await inspectCleanRedactCodeblock(Object.getPrototypeOf(rawOutput), 'js', {
+ ? await util.inspectCleanRedactCodeblock(Object.getPrototypeOf(rawOutput), 'js', {
depth: 1,
getters: true,
showHidden: true
@@ -169,7 +138,7 @@ export default class EvalCommand extends BushCommand {
embed.setTitle(`${emojis.errorFull} Code was not able to be evaluated.`).setColor(colors.error);
if (inputTS) embed.addField('📥 Input (typescript)', inputTS).addField('📥 Input (transpiled javascript)', inputJS);
else embed.addField('📥 Input', inputJS);
- embed.addField('📤 Output', await inspectCleanRedactCodeblock(e?.stack || e, 'js'));
+ embed.addField('📤 Output', await util.inspectCleanRedactCodeblock(e?.stack || e, 'js'));
}
embed.setTimestamp().setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true }));
diff --git a/src/commands/utilities/decode.ts b/src/commands/utilities/decode.ts
index 97ff444..aa3d455 100644
--- a/src/commands/utilities/decode.ts
+++ b/src/commands/utilities/decode.ts
@@ -89,43 +89,21 @@ export default class DecodeCommand extends BushCommand {
}
public async exec(
- message: BushMessage,
+ message: BushMessage | AkairoMessage,
{ from, to, data }: { from: BufferEncoding; to: BufferEncoding; data: string }
): Promise<unknown> {
- const encodeOrDecode = message?.util?.parsed?.alias?.charAt(0).toUpperCase() + message?.util?.parsed?.alias?.slice(1);
+ const encodeOrDecode = util.capitalizeFirstLetter(message?.util?.parsed?.alias) || 'Decoded';
const decodedEmbed = new MessageEmbed()
.setTitle(`${encodeOrDecode} Information`)
- .addField('📥 Input', await this.client.util.codeblock(data, 1024));
+ .addField('📥 Input', await util.inspectCleanRedactCodeblock(data, null));
try {
const decoded = Buffer.from(data, from).toString(to);
- decodedEmbed
- .setColor(this.client.util.colors.success)
- .addField('📤 Output', await this.client.util.codeblock(decoded, 1024));
- } catch (error) {
- decodedEmbed
- .setColor(this.client.util.colors.error)
- .addField(`📤 Error ${encodeOrDecode.slice(1)}ing`, await this.client.util.codeblock(error.stack, 1024));
- }
- return await message.util.send({ embeds: [decodedEmbed], allowedMentions: AllowedMentions.none() });
- }
-
- public async execSlash(
- message: AkairoMessage,
- { from, to, data }: { from: BufferEncoding; to: BufferEncoding; data: string }
- ): Promise<unknown> {
- const decodedEmbed = new MessageEmbed()
- .setTitle(`Decoded Information`)
- .addField('📥 Input', await this.client.util.codeblock(data, 1024));
- try {
- const decoded = Buffer.from(data, from).toString(to);
- decodedEmbed
- .setColor(this.client.util.colors.success)
- .addField('📤 Output', await this.client.util.codeblock(decoded, 1024));
+ decodedEmbed.setColor(util.colors.success).addField('📤 Output', await util.inspectCleanRedactCodeblock(decoded, null));
} catch (error) {
decodedEmbed
- .setColor(this.client.util.colors.error)
- .addField(`📤 Error decoding`, await this.client.util.codeblock(error.stack, 1024));
+ .setColor(util.colors.error)
+ .addField(`📤 Error ${encodeOrDecode.slice(1)}ing`, await util.inspectCleanRedactCodeblock(error.stack, null));
}
- return await message.interaction.reply({ embeds: [decodedEmbed], allowedMentions: AllowedMentions.none() });
+ return await message.util.reply({ embeds: [decodedEmbed], allowedMentions: AllowedMentions.none() });
}
}
diff --git a/src/commands/utilities/price.ts b/src/commands/utilities/price.ts
index 21781d1..d04544b 100644
--- a/src/commands/utilities/price.ts
+++ b/src/commands/utilities/price.ts
@@ -1,5 +1,5 @@
import { Constants } from 'discord-akairo';
-import { ColorResolvable, MessageEmbed } from 'discord.js';
+import { MessageEmbed } from 'discord.js';
import Fuse from 'fuse.js';
import fetch from 'node-fetch';
import { BushCommand, BushMessage } from '../../lib';
@@ -47,6 +47,8 @@ interface AuctionAverages {
};
}
+type Results = [Bazaar, LowestBIN, LowestBIN, AuctionAverages];
+
export default class PriceCommand extends BushCommand {
public constructor() {
super('price', {
@@ -99,113 +101,81 @@ export default class PriceCommand extends BushCommand {
public async exec(message: BushMessage, { item, strict }: { item: string; strict: boolean }): Promise<unknown> {
const errors = new Array<string>();
- const [bazaar, currentLowestBIN, averageLowestBIN, auctionAverages]: [Bazaar, LowestBIN, LowestBIN, AuctionAverages] =
+ const [bazaar, currentLowestBIN, averageLowestBIN, auctionAverages] = (
await Promise.all([
- fetch('https://api.hypixel.net/skyblock/bazaar')
- .then((resp) => resp.json())
- .catch(() => errors.push('bazaar')),
- fetch('https://moulberry.codes/lowestbin.json')
- .then((resp) => resp.json())
- .catch(() => errors.push('current lowest BIN')),
- fetch('https://moulberry.codes/auction_averages_lbin/3day.json')
- .then((resp) => resp.json())
- .catch(() => errors.push('average Lowest BIN')),
- fetch('https://moulberry.codes/auction_averages/3day.json')
- .then((resp) => resp.json())
- .catch(() => errors.push('auction average'))
- ]);
+ fetch('https://api.hypixel.net/skyblock/bazaar').catch(() => errors.push('bazaar')),
+ fetch('https://moulberry.codes/lowestbin.json').catch(() => errors.push('current lowest BIN')),
+ fetch('https://moulberry.codes/auction_averages_lbin/3day.json').catch(() => errors.push('average Lowest BIN')),
+ fetch('https://moulberry.codes/auction_averages/3day.json').catch(() => errors.push('auction average'))
+ ])
+ ).map((request) => (typeof request === 'number' ? null : request.json())) as unknown as Results;
let parsedItem = item.toString().toUpperCase().replace(/ /g, '_').replace(/'S/g, '');
const priceEmbed = new MessageEmbed();
if (errors?.length) {
- priceEmbed.setFooter(`Could not fetch data from ${this.client.util.oxford(errors, 'and', '')}`);
+ priceEmbed.setFooter(`Could not fetch data from ${util.oxford(errors, 'and', '')}`);
}
- //combines all the item names from each
- const itemNames = Array.from(
- new Set(
- (averageLowestBIN ? Object.keys(averageLowestBIN) : []).concat(
- currentLowestBIN ? Object.keys(currentLowestBIN) : [],
- auctionAverages ? Object.keys(auctionAverages) : [],
- bazaar?.products ? Object.keys(bazaar.products) : []
- )
- )
+ // create a set from all the item names so that there are no duplicates for the fuzzy search
+ const itemNames = new Set(
+ ...Object.keys(averageLowestBIN || {}),
+ ...Object.keys(currentLowestBIN || {}),
+ ...Object.keys(auctionAverages || {}),
+ ...Object.keys(bazaar?.products || {})
);
// fuzzy search
- if (!strict) {
- parsedItem = new Fuse(itemNames)?.search(parsedItem)[0]?.item;
- }
+ if (!strict) parsedItem = new Fuse(Array.from(itemNames))?.search(parsedItem)[0]?.item;
- // If bazaar item then it there should not be any ah data
+ // iif bazaar item then it there should not be any ah data
if (bazaar['products'][parsedItem]) {
const bazaarPriceEmbed = new MessageEmbed()
- .setColor(
- errors?.length
- ? (this.client.util.emojis.warn as ColorResolvable)
- : (this.client.util.colors.success as ColorResolvable)
+ .setColor(errors?.length ? util.colors.warn : util.colors.success)
+ .setTitle(`Bazaar Information for **${parsedItem}**`)
+ .addField('Sell Price', addBazaarInformation('sellPrice', 2, true))
+ .addField('Buy Price', addBazaarInformation('buyPrice', 2, true))
+ .addField(
+ 'Margin',
+ (+addBazaarInformation('buyPrice', 2, false) - +addBazaarInformation('sellPrice', 2, false)).toLocaleString()
)
- .setTitle(`Bazaar Information for \`${parsedItem}\``)
- .addField('Sell Price', Bazaar('sellPrice', 2, true))
- .addField('Buy Price', Bazaar('buyPrice', 2, true))
- .addField('Margin', (Number(Bazaar('buyPrice', 2, false)) - Number(Bazaar('sellPrice', 2, false))).toLocaleString())
- .addField('Current Sell Orders', Bazaar('sellOrders', 0, true))
- .addField('Current Buy Orders', Bazaar('buyOrders', 0, true));
+ .addField('Current Sell Orders', addBazaarInformation('sellOrders', 0, true))
+ .addField('Current Buy Orders', addBazaarInformation('buyOrders', 0, true));
return await message.util.reply({ embeds: [bazaarPriceEmbed] });
}
- // Checks if the item exists in any of the action information otherwise it is not a valid item
+ // checks if the item exists in any of the action information otherwise it is not a valid item
if (currentLowestBIN?.[parsedItem] || averageLowestBIN?.[parsedItem] || auctionAverages?.[parsedItem]) {
priceEmbed
- .setColor(this.client.util.colors.success)
+ .setColor(util.colors.success)
.setTitle(`Price Information for \`${parsedItem}\``)
.setFooter('All information is based on the last 3 days.');
} else {
const errorEmbed = new MessageEmbed();
errorEmbed
- .setColor(this.client.util.colors.error)
- .setDescription(
- `${this.client.util.emojis.error} \`${parsedItem}\` is not a valid item id, or it has no auction data.`
- );
+ .setColor(util.colors.error)
+ .setDescription(`${util.emojis.error} \`${parsedItem}\` is not a valid item id, or it has no auction data.`);
return await message.util.reply({ embeds: [errorEmbed] });
}
- if (currentLowestBIN?.[parsedItem]) {
- const currentLowestBINPrice = currentLowestBIN[parsedItem].toLocaleString();
- priceEmbed.addField('Current Lowest BIN', currentLowestBINPrice);
- }
- if (averageLowestBIN?.[parsedItem]) {
- const averageLowestBINPrice = averageLowestBIN[parsedItem].toLocaleString();
- priceEmbed.addField('Average Lowest BIN', averageLowestBINPrice);
- }
- if (auctionAverages?.[parsedItem]?.price) {
- const auctionAveragesPrice = auctionAverages[parsedItem].price.toLocaleString();
- priceEmbed.addField('Average Auction Price', auctionAveragesPrice);
- }
- if (auctionAverages?.[parsedItem]?.count) {
- const auctionAveragesCountPrice = auctionAverages[parsedItem].count.toLocaleString();
- priceEmbed.addField('Average Auction Count', auctionAveragesCountPrice);
- }
- if (auctionAverages?.[parsedItem]?.sales) {
- const auctionAveragesSalesPrice = auctionAverages[parsedItem].sales.toLocaleString();
- priceEmbed.addField('Average Auction Sales', auctionAveragesSalesPrice);
- }
- if (auctionAverages?.[parsedItem]?.clean_price) {
- const auctionAveragesCleanPrice = auctionAverages[parsedItem].clean_price.toLocaleString();
- priceEmbed.addField('Average Auction Clean Price', auctionAveragesCleanPrice);
- }
- if (auctionAverages?.[parsedItem]?.clean_sales) {
- const auctionAveragesCleanSales = auctionAverages[parsedItem].clean_sales.toLocaleString();
- priceEmbed.addField('Average Auction Clean Sales', auctionAveragesCleanSales);
- }
+ addPrice('Current Lowest BIN', currentLowestBIN?.[parsedItem]);
+ addPrice('Average Lowest BIN', averageLowestBIN?.[parsedItem]);
+ addPrice('Average Auction Price', auctionAverages?.[parsedItem]?.price);
+ addPrice('Average Auction Count', auctionAverages?.[parsedItem]?.count);
+ addPrice('Average Auction Sales', auctionAverages?.[parsedItem]?.sales);
+ addPrice('Average Auction Clean Price', auctionAverages?.[parsedItem]?.clean_price);
+ addPrice('Average Auction Clean Sales', auctionAverages?.[parsedItem]?.clean_sales);
+
return await message.util.reply({ embeds: [priceEmbed] });
- //Helper functions
- function Bazaar(Information: string, digits: number, commas: boolean): string {
+ // helper functions
+ function addBazaarInformation(Information: string, digits: number, commas: boolean): string {
const price = bazaar?.products[parsedItem]?.quick_status?.[Information];
- const a = Number(Number(price).toFixed(digits));
- return commas ? a?.toLocaleString() : a?.toString();
+ const roundedPrice = Number(Number(price).toFixed(digits));
+ return commas ? roundedPrice?.toLocaleString() : roundedPrice?.toString();
+ }
+ function addPrice(name: string, price: number | undefined) {
+ if (price) priceEmbed.addField(name, price.toFixed(2).toLocaleString());
}
}
}
diff --git a/src/inhibitors/noCache.ts b/src/inhibitors/noCache.ts
index 9d6e560..9bddedd 100644
--- a/src/inhibitors/noCache.ts
+++ b/src/inhibitors/noCache.ts
@@ -11,8 +11,8 @@ export default class NoCacheInhibitor extends BushInhibitor {
public async exec(message: BushMessage | BushSlashMessage): Promise<boolean> {
if (this.client.isOwner(message.author)) return false;
- for (const property in this.client.cache) {
- if (property === undefined || property === null) {
+ for (const property in this.client.cache.global) {
+ if (!this.client.cache.global[property]) {
this.client.console.debug(`NoCacheInhibitor blocked message.`);
return true;
}
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index 8599e76..c283eb9 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -261,7 +261,9 @@ export class BushClient extends AkairoClient {
/** Starts the bot */
public async start(): Promise<void> {
- global.client = this; // makes the client a global object
+ // global objects
+ global.client = this;
+ global.util = this.util;
try {
await this._init();
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index 1ba94c2..e8fe7fa 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -38,7 +38,7 @@ import {
} from 'discord.js';
import got from 'got';
import humanizeDuration from 'humanize-duration';
-import { promisify } from 'util';
+import { inspect, InspectOptions, promisify } from 'util';
import { ActivePunishment, ActivePunishmentType } from '../../models/ActivePunishment';
import { BushNewsChannel } from '../discord.js/BushNewsChannel';
import { BushTextChannel } from '../discord.js/BushTextChannel';
@@ -449,21 +449,56 @@ export class BushClientUtil extends ClientUtil {
/**
* Surrounds text in a code block with the specified language and puts it in a hastebin if its too long.
*
- * * Embed Description Limit = 2048 characters
+ * * Embed Description Limit = 4096 characters
* * Embed Field Limit = 1024 characters
*/
- public async codeblock(code: string, length: number, language: 'ts' | 'js' | 'sh' | 'json' | '' = ''): Promise<string> {
+ public async codeblock(code: string, length: number, language?: 'ts' | 'js' | 'sh' | 'json'): Promise<string> {
let hasteOut = '';
const tildes = '```';
- const formattingLength = 2 * tildes.length + language.length + 2 * '\n'.length;
+ const formattingLength = 2 * tildes.length + language?.length ?? 0 + 2 * '\n'.length;
if (code.length + formattingLength >= length) hasteOut = 'Too large to display. Hastebin: ' + (await this.haste(code));
const code2 = hasteOut ? code.substring(0, length - (hasteOut.length + '\n'.length + formattingLength)) : code;
return (
- tildes + language + '\n' + Util.cleanCodeBlockContent(code2) + '\n' + tildes + (hasteOut.length ? '\n' + hasteOut : '')
+ tildes + language ??
+ '' + '\n' + Util.cleanCodeBlockContent(code2) + '\n' + tildes + (hasteOut.length ? '\n' + hasteOut : '')
);
}
+ private mapCredential(old: string) {
+ const mapping = {
+ ['token']: 'Main Token',
+ ['devToken']: 'Dev Token',
+ ['betaToken']: 'Beta Token',
+ ['hypixelApiKey']: 'Hypixel Api Key'
+ };
+ return mapping[old] || old;
+ }
+
+ /**
+ * Redacts credentials from a string
+ */
+ public redact(text: string) {
+ for (const credentialName in client.config.credentials) {
+ const credential = client.config.credentials[credentialName];
+ const replacement = this.mapCredential(credentialName);
+ const escapeRegex = /[.*+?^${}()|[\]\\]/g;
+ text = text.replace(new RegExp(credential.toString().replace(escapeRegex, '\\$&'), 'g'), `[${replacement} Omitted]`);
+ text = text.replace(
+ new RegExp([...credential.toString()].reverse().join('').replace(escapeRegex, '\\$&'), 'g'),
+ `[${replacement} Omitted]`
+ );
+ }
+ return text;
+ }
+
+ public async inspectCleanRedactCodeblock(input: any, language: 'ts' | 'js', inspectOptions?: InspectOptions) {
+ input = typeof input !== 'string' && inspectOptions !== undefined ? inspect(input, inspectOptions) : input;
+ input = Util.cleanCodeBlockContent(input);
+ input = this.redact(input);
+ return client.util.codeblock(input, 1024, language);
+ }
+
public async slashRespond(
interaction: CommandInteraction,
responseOptions: BushSlashSendMessageType | BushSlashEditMessageType
@@ -754,4 +789,8 @@ export class BushClientUtil extends ClientUtil {
const autoModPhases = await message.guild.getSetting('autoModPhases');
if (autoModPhases.includes(message.content.toString()) && message.deletable) message.delete();
}
+
+ public capitalizeFirstLetter(string: string): string {
+ return string.charAt(0)?.toUpperCase() + string.slice(1);
+ }
}
diff --git a/src/lib/extensions/global.d.ts b/src/lib/extensions/global.d.ts
index 8c7a117..d4c5f61 100644
--- a/src/lib/extensions/global.d.ts
+++ b/src/lib/extensions/global.d.ts
@@ -1,9 +1,12 @@
import { BushClient } from './discord-akairo/BushClient';
+import { BushClientUtil } from './discord-akairo/BushClientUtil';
declare global {
namespace NodeJS {
export interface Global {
client: BushClient;
+ util: BushClientUtil;
}
}
const client: BushClient;
+ const util: BushClientUtil;
}