diff --git a/squeebot.repo.json b/squeebot.repo.json index 66e3577..7305833 100644 --- a/squeebot.repo.json +++ b/squeebot.repo.json @@ -43,7 +43,7 @@ }, { "name": "utility", - "version": "3.1.10" + "version": "3.2.1" } ], "typescript": true diff --git a/utility/plugin.json b/utility/plugin.json index d066008..f574b73 100644 --- a/utility/plugin.json +++ b/utility/plugin.json @@ -2,9 +2,14 @@ "main": "plugin.js", "name": "utility", "description": "Utility commands and math operations", - "version": "3.1.10", - "tags": ["commands", "tools"], - "dependencies": ["simplecommands"], + "version": "3.2.1", + "tags": [ + "commands", + "tools" + ], + "dependencies": [ + "simplecommands" + ], "npmDependencies": [ "mathjs@^9.4.4", "convert-units@^3.0.0-beta.2" diff --git a/utility/plugin.ts b/utility/plugin.ts index 8bde27e..136de5c 100644 --- a/utility/plugin.ts +++ b/utility/plugin.ts @@ -6,11 +6,15 @@ import { Plugin, Configurable, EventListener, - DependencyLoad + DependencyLoad, } from '@squeebot/core/lib/plugin'; import { IMessage, MessageResolver } from '@squeebot/core/lib/types'; -import { httpGET, parseTimeToSeconds, readableTime } from '@squeebot/core/lib/common'; +import { + httpGET, + parseTimeToSeconds, + readableTime, +} from '@squeebot/core/lib/common'; import { logger } from '@squeebot/core/lib/core'; import { @@ -24,17 +28,11 @@ import { ASCIIBinaryConverter, ASCIIHexConverter, base64Converter, - baseConverter + baseConverter, } from './convert'; type CEXResponse = { [key: string]: number }; -const cexCache: { [key: string]: number | CEXResponse } = { - expiry: 0, - date: 0, - cache: {}, -}; - // Run mathjs in a separate thread to avoid the killing of the main process function opMath(expression: string): Promise { return new Promise((resolve, reject) => { @@ -103,7 +101,7 @@ function pingTcpServer(host: string, port: number): Promise { } } - const pingHost = net.connect({port, host}, () => { + const pingHost = net.connect({ port, host }, () => { timeA = new Date().getTime(); returnResults(true, timeA - timeB); pingHost.end(); @@ -135,7 +133,13 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { cmds.push({ name: 'binary', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { try { const result = ASCIIBinaryConverter(msg.text, simplified); msg.resolve(`> ${result}`); @@ -145,12 +149,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Encode/decode binary (ASCII only)', - usage: ' ' + usage: ' ', }); cmds.push({ name: 'hexstr', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { try { const result = ASCIIHexConverter(msg.text, simplified); msg.resolve(`> ${result}`); @@ -160,12 +170,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Encode/decode hexadecimal (ASCII only)', - usage: ' ' + usage: ' ', }); cmds.push({ name: 'base64', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { try { const result = base64Converter(msg.text, simplified); msg.resolve(`> ${result}`); @@ -175,12 +191,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Encode/decode base64 (ASCII only)', - usage: ' ' + usage: ' ', }); cmds.push({ name: 'numsys', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { try { const result = baseConverter(simplified); msg.resolve(`> ${result}`); @@ -191,23 +213,35 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { }, description: 'Convert a value into a value in another numbering system.', usage: ' ', - aliases: ['convertnumbers', 'cvnums'] + aliases: ['convertnumbers', 'cvnums'], }); cmds.push({ name: 'convertseconds', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { msg.resolve(readableTime(parseInt(simplified[0], 10))); return true; }, description: 'Convert seconds to years days hours minutes seconds.', usage: '', - aliases: ['cvs', 'parseseconds'] + aliases: ['cvs', 'parseseconds'], }); cmds.push({ name: 'converttime', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { const str = msg.text.split(' ').slice(1).join(' '); if (!str) { @@ -219,13 +253,20 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Convert ywdhms to seconds.', - usage: '[y] [w] [d] [h] [m] [s]', - aliases: ['cvt', 'parsetime'] + usage: + '[y] [w] [d] [h] [m] [s]', + aliases: ['cvt', 'parsetime'], }); cmds.push({ name: 'reconverttime', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { const str = msg.text.split(' ').slice(1).join(' '); if (!str) { @@ -238,12 +279,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, - aliases: ['rcvt'] + aliases: ['rcvt'], }); cmds.push({ name: 'eval', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (!simplified[0]) { return true; } @@ -261,55 +308,83 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { }, aliases: ['math', 'calc'], usage: '', - description: 'Evaluate a math expression (See https://mathjs.org/)' + description: 'Evaluate a math expression (See https://mathjs.org/)', }); cmds.push({ name: 'userid', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { msg.resolve('Your userId is %s.', msg.fullSenderID); return true; }, description: 'Display your userId (internal user identification)', - hidden: true + hidden: true, }); cmds.push({ name: 'roomid', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { msg.resolve('Current roomId is %s.', msg.fullRoomID); return true; }, description: 'Display the internal identification of this room', - hidden: true + hidden: true, }); cmds.push({ name: 'serverid', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (msg.target && msg.target.server) { msg.resolve('Current server ID is s:%s.', msg.target.server); return true; } - msg.resolve('This protocol does not specify a server. ' + - 'Either the protocol is for a single server only or the server variable is not supported.'); + msg.resolve( + 'This protocol does not specify a server. ' + + 'Either the protocol is for a single server only or the server variable is not supported.' + ); return true; }, description: 'Display the internal identification of this room', - hidden: true + hidden: true, }); cmds.push({ name: 'rgb2hex', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (!simplified[0]) { return true; } const fullmsg = msg.text.split(' ').slice(1).join(' '); - const channels = fullmsg.match(/(rgb)?\(?(\d{1,3}),?\s(\d{1,3}),?\s(\d{1,3})\)?/i); + const channels = fullmsg.match( + /(rgb)?\(?(\d{1,3}),?\s(\d{1,3}),?\s(\d{1,3})\)?/i + ); if (!channels || channels[2] == null) { msg.resolve('Invalid parameter'); return true; @@ -328,18 +403,26 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Convert RGB to HEX colors', - usage: '[rgb](, , )| ' + usage: '[rgb](, , )| ', }); cmds.push({ name: 'rgb2hsl', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (!simplified[0]) { return true; } const fullmsg = msg.text.split(' ').slice(1).join(' '); - const channels = fullmsg.match(/(rgb)?\(?(\d{1,3}),?\s(\d{1,3}),?\s(\d{1,3})\)?/i); + const channels = fullmsg.match( + /(rgb)?\(?(\d{1,3}),?\s(\d{1,3}),?\s(\d{1,3})\)?/i + ); if (!channels || channels[2] == null) { msg.resolve('Invalid parameter'); return true; @@ -359,12 +442,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Convert RGB to HSL colors', - usage: '[rgb](, , )| ' + usage: '[rgb](, , )| ', }); cmds.push({ name: 'hex2rgb', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (!simplified[0]) { return true; } @@ -389,12 +478,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; }, description: 'Convert HEX to RGB colors', - usage: '#|#' + usage: '#|#', }); cmds.push({ name: 'isup', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (!simplified[0]) { msg.resolve('Please specify host name!'); return true; @@ -432,12 +527,18 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { description: 'Ping a host', usage: ' ', aliases: ['tcpup', 'tping'], - hidden: true + hidden: true, }); cmds.push({ name: 'convert', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { const tqnt = parseFloat(simplified[0]); if (isNaN(tqnt)) { msg.resolve('Please specify a quantity, either an integer or a float!'); @@ -484,8 +585,10 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { const srcdesc = convert().describe(src); const dstdesc = convert().describe(dst); - const bsrcdesc = (Math.floor(tqnt) !== 1) ? srcdesc.plural : srcdesc.singular; - const bdstdesc = (Math.floor(res) !== 1) ? dstdesc.plural : dstdesc.singular; + const bsrcdesc = + Math.floor(tqnt) !== 1 ? srcdesc.plural : srcdesc.singular; + const bdstdesc = + Math.floor(res) !== 1 ? dstdesc.plural : dstdesc.singular; msg.resolve(` ${tqnt} ${bsrcdesc} => ${res} ${bdstdesc}`); return true; @@ -496,14 +599,20 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { }, description: 'Convert between quantities in different units.', usage: ' ', - aliases: ['cv', 'unit'] + aliases: ['cv', 'unit'], }); cmds.push({ name: 'currency', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { - let ctw: CEXResponse | null = cexCache.cache as CEXResponse; - if (cexCache.expiry < Date.now()) { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { + let ctw: CEXResponse | null = plugin.cexCache.cache as CEXResponse; + if (plugin.cexCache.expiry < Date.now()) { let fetched; try { const data = await httpGET('https://api.exchangerate.host/latest'); @@ -514,21 +623,29 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { } if (!ctw || !fetched.rates) { - msg.resolve('Could not fetch currency exchange rates at this time. Please try again later.'); + msg.resolve( + 'Could not fetch currency exchange rates at this time. Please try again later.' + ); return true; } - cexCache.cache = fetched.rates; - cexCache.date = fetched.date; - cexCache.expiry = Date.now() + 86400000; // day - ctw = cexCache.cache as CEXResponse; + plugin.cexCache.cache = fetched.rates; + plugin.cexCache.date = fetched.date; + plugin.cexCache.expiry = Date.now() + 86400000; // day + ctw = plugin.cexCache.cache as CEXResponse; } if (simplified[0] === 'date') { - msg.resolve('Currency exchange rates are as of %s', cexCache.date); + msg.resolve( + 'Currency exchange rates are as of %s', + plugin.cexCache.date + ); return true; } else if (simplified[0] === 'list') { - msg.resolve('Currently supported currencies: EUR, %s', Object.keys(cexCache.cache).join(', ')); + msg.resolve( + 'Currently supported currencies: EUR, %s', + Object.keys(plugin.cexCache.cache).join(', ') + ); return true; } @@ -568,18 +685,24 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { return true; } - const amnt = (ctw[t] * n / ctw[f]).toFixed(4); + const amnt = ((ctw[t] * n) / ctw[f]).toFixed(4); msg.resolve('%f %s => %f %s', n, f, amnt, t); return true; }, description: 'Convert between currencies.', usage: ' | [date | list] [] []', - aliases: ['cex', 'exchange'] + aliases: ['cex', 'exchange'], }); cmds.push({ name: 'randomnumber', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { if (simplified.length < 2) { msg.resolve('Too few arguments!'); return true; @@ -598,8 +721,13 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { min = max; max = realMax; } - if (isNaN(count)) { count = 1; } - if (String(Math.abs(min)).length > 9 || String(Math.abs(max)).length > 9) { + if (isNaN(count)) { + count = 1; + } + if ( + String(Math.abs(min)).length > 9 || + String(Math.abs(max)).length > 9 + ) { msg.resolve('The numbers are too large!'); return true; } @@ -616,15 +744,23 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { }, description: 'Generate a random number between and .', usage: ' []', - aliases: ['rnum', 'rand', 'rng'] + aliases: ['rnum', 'rand', 'rng'], }); // FIXME: temporary code for removal cmds.push({ name: 'cmtest', - execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise => { + execute: async ( + msg: IMessage, + msr: MessageResolver, + spec: any, + prefix: string, + ...simplified: any[] + ): Promise => { console.log(simplified); - msg.resolve(`argument 1: '${simplified[0]}' argument 2: '${simplified[1]}'`); + msg.resolve( + `argument 1: '${simplified[0]}' argument 2: '${simplified[1]}'` + ); return true; }, description: 'Test the command argument parser', @@ -632,17 +768,25 @@ function addCommands(plugin: UtilityPlugin, commands: any): void { hidden: true, }); - commands.registerCommand(cmds.map((x: any) => { - x.plugin = plugin.manifest.name; - return x; - })); + commands.registerCommand( + cmds.map((x: any) => { + x.plugin = plugin.manifest.name; + return x; + }) + ); } @Configurable({ ipfsGateway: 'https://ipfs.io', - randomMax: 64 + randomMax: 64, }) class UtilityPlugin extends Plugin { + public cexCache: { [key: string]: number | CEXResponse } = { + expiry: 0, + date: 0, + cache: {}, + }; + @DependencyLoad('simplecommands') addCommands(cmd: any): void { addCommands(this, cmd); @@ -652,6 +796,9 @@ class UtilityPlugin extends Plugin { public unloadEventHandler(plugin: string | Plugin): void { if (plugin === this.name || plugin === this) { wipeCaches(); + this.cexCache.expiry = 0; + this.cexCache.date = 0; + this.cexCache.cache = {}; this.emit('pluginUnloaded', this); } }