weirdness

This commit is contained in:
Evert Prants 2022-03-08 21:07:25 +02:00
parent 1406f46b2e
commit 60b55f582b
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
3 changed files with 228 additions and 76 deletions

View File

@ -43,7 +43,7 @@
},
{
"name": "utility",
"version": "3.1.10"
"version": "3.2.1"
}
],
"typescript": true

View File

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

View File

@ -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<string> {
return new Promise((resolve, reject) => {
@ -103,7 +101,7 @@ function pingTcpServer(host: string, port: number): Promise<number> {
}
}
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '<ENCODE/DECODE> <message>'
usage: '<ENCODE/DECODE> <message>',
});
cmds.push({
name: 'hexstr',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '<ENCODE/DECODE> <string>'
usage: '<ENCODE/DECODE> <string>',
});
cmds.push({
name: 'base64',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '<ENCODE/DECODE> <string>'
usage: '<ENCODE/DECODE> <string>',
});
cmds.push({
name: 'numsys',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '<value> <bin/dec/hex/oct> <bin/dec/hex/oct>',
aliases: ['convertnumbers', 'cvnums']
aliases: ['convertnumbers', 'cvnums'],
});
cmds.push({
name: 'convertseconds',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
msg.resolve(readableTime(parseInt(simplified[0], 10)));
return true;
},
description: 'Convert seconds to years days hours minutes seconds.',
usage: '<seconds>',
aliases: ['cvs', 'parseseconds']
aliases: ['cvs', 'parseseconds'],
});
cmds.push({
name: 'converttime',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '[<years>y] [<weeks>w] [<days>d] [<hours>h] [<minutes>m] [<seconds>s]',
aliases: ['cvt', 'parsetime']
usage:
'[<years>y] [<weeks>w] [<days>d] [<hours>h] [<minutes>m] [<seconds>s]',
aliases: ['cvt', 'parsetime'],
});
cmds.push({
name: 'reconverttime',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
if (!simplified[0]) {
return true;
}
@ -261,55 +308,83 @@ function addCommands(plugin: UtilityPlugin, commands: any): void {
},
aliases: ['math', 'calc'],
usage: '<expression>',
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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](<r>, <g>, <b>)|<r> <g> <b>'
usage: '[rgb](<r>, <g>, <b>)|<r> <g> <b>',
});
cmds.push({
name: 'rgb2hsl',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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](<r>, <g>, <b>)|<r> <g> <b>'
usage: '[rgb](<r>, <g>, <b>)|<r> <g> <b>',
});
cmds.push({
name: 'hex2rgb',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '#<r><g><b>|#<rr><gg><bb>'
usage: '#<r><g><b>|#<rr><gg><bb>',
});
cmds.push({
name: 'isup',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '<host> <port>',
aliases: ['tcpup', 'tping'],
hidden: true
hidden: true,
});
cmds.push({
name: 'convert',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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: '<number> <from unit> <to unit>',
aliases: ['cv', 'unit']
aliases: ['cv', 'unit'],
});
cmds.push({
name: 'currency',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
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<boolean> => {
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: '<number> | [date | list] [<from currency>] [<to currency>]',
aliases: ['cex', 'exchange']
aliases: ['cex', 'exchange'],
});
cmds.push({
name: 'randomnumber',
execute: async (msg: IMessage, msr: MessageResolver, spec: any, prefix: string, ...simplified: any[]): Promise<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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 <min> and <max>.',
usage: '<min> <max> [<count>]',
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<boolean> => {
execute: async (
msg: IMessage,
msr: MessageResolver,
spec: any,
prefix: string,
...simplified: any[]
): Promise<boolean> => {
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);
}
}