823 lines
20 KiB
TypeScript
823 lines
20 KiB
TypeScript
import path from 'path';
|
|
import net from 'net';
|
|
import { fork } from 'child_process';
|
|
|
|
import {
|
|
Plugin,
|
|
Configurable,
|
|
EventListener,
|
|
DependencyLoad,
|
|
} from '@squeebot/core/lib/plugin';
|
|
|
|
import { IMessage, MessageResolver } from '@squeebot/core/lib/types';
|
|
import {
|
|
httpGET,
|
|
parseTimeToSeconds,
|
|
readableTime,
|
|
} from '@squeebot/core/lib/common';
|
|
|
|
import { logger } from '@squeebot/core/lib/core';
|
|
import {
|
|
createUnitIndex,
|
|
getUnitAbbreviation,
|
|
hexToRgb,
|
|
rgbToHex,
|
|
RGBToHSL,
|
|
convert,
|
|
wipeCaches,
|
|
ASCIIBinaryConverter,
|
|
ASCIIHexConverter,
|
|
base64Converter,
|
|
baseConverter,
|
|
} from './convert';
|
|
|
|
type CEXResponse = { [key: string]: number };
|
|
|
|
// 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) => {
|
|
// Fork the script
|
|
const mathThread = fork(path.join(__dirname, 'math.js'));
|
|
|
|
let done = false;
|
|
|
|
// Time the request out when user enters something too complex
|
|
const timeItOut = setTimeout(() => {
|
|
mathThread.kill('SIGKILL');
|
|
done = true;
|
|
return reject(new Error('Timed out'));
|
|
}, 8000);
|
|
|
|
// Send data to the thread to process
|
|
mathThread.send(expression);
|
|
|
|
// Recieve data
|
|
mathThread.on('message', (chunk) => {
|
|
clearTimeout(timeItOut);
|
|
|
|
if (done) {
|
|
return;
|
|
}
|
|
const line = chunk.toString().trim();
|
|
|
|
if (line.length > 280) {
|
|
return reject(new Error('The response was too large'));
|
|
}
|
|
|
|
done = true;
|
|
|
|
if (line === 'null') {
|
|
return reject(new Error('Nothing was returned'));
|
|
}
|
|
|
|
resolve(line);
|
|
});
|
|
|
|
mathThread.on('exit', () => {
|
|
clearTimeout(timeItOut);
|
|
|
|
if (!done) {
|
|
reject(new Error('Nothing was returned'));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function pingTcpServer(host: string, port: number): Promise<number> {
|
|
return new Promise((resolve, reject) => {
|
|
let isFinished = false;
|
|
let timeA = new Date().getTime();
|
|
const timeB = new Date().getTime();
|
|
|
|
function returnResults(status: boolean, info: number | Error): void {
|
|
if (!isFinished) {
|
|
isFinished = true;
|
|
|
|
if (info instanceof Error) {
|
|
return reject(info);
|
|
}
|
|
|
|
resolve(info);
|
|
}
|
|
}
|
|
|
|
const pingHost = net.connect({ port, host }, () => {
|
|
timeA = new Date().getTime();
|
|
returnResults(true, timeA - timeB);
|
|
pingHost.end();
|
|
pingHost.destroy();
|
|
});
|
|
|
|
pingHost.setTimeout(5000);
|
|
|
|
pingHost.on('timeout', () => {
|
|
pingHost.end();
|
|
pingHost.destroy();
|
|
returnResults(false, new Error('timeout'));
|
|
});
|
|
|
|
pingHost.on('error', (e) => {
|
|
pingHost.end();
|
|
pingHost.destroy();
|
|
returnResults(false, e);
|
|
});
|
|
|
|
pingHost.on('close', () => {
|
|
returnResults(false, new Error('closed'));
|
|
});
|
|
});
|
|
}
|
|
|
|
function addCommands(plugin: UtilityPlugin, commands: any): void {
|
|
const cmds = [];
|
|
|
|
cmds.push({
|
|
name: 'binary',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
try {
|
|
const result = ASCIIBinaryConverter(msg.text, simplified);
|
|
msg.resolve(`> ${result}`);
|
|
} catch (e: any) {
|
|
msg.resolve('Failed to convert.');
|
|
}
|
|
return true;
|
|
},
|
|
description: 'Encode/decode binary (ASCII only)',
|
|
usage: '<ENCODE/DECODE> <message>',
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'hexstr',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
try {
|
|
const result = ASCIIHexConverter(msg.text, simplified);
|
|
msg.resolve(`> ${result}`);
|
|
} catch (e: any) {
|
|
msg.resolve('Failed to convert.');
|
|
}
|
|
return true;
|
|
},
|
|
description: 'Encode/decode hexadecimal (ASCII only)',
|
|
usage: '<ENCODE/DECODE> <string>',
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'base64',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
try {
|
|
const result = base64Converter(msg.text, simplified);
|
|
msg.resolve(`> ${result}`);
|
|
} catch (e: any) {
|
|
msg.resolve('Failed to convert.');
|
|
}
|
|
return true;
|
|
},
|
|
description: 'Encode/decode base64 (ASCII only)',
|
|
usage: '<ENCODE/DECODE> <string>',
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'numsys',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
try {
|
|
const result = baseConverter(simplified);
|
|
msg.resolve(`> ${result}`);
|
|
} catch (e: any) {
|
|
msg.resolve('Failed to convert.');
|
|
}
|
|
return true;
|
|
},
|
|
description: 'Convert a value into a value in another numbering system.',
|
|
usage: '<value> <bin/dec/hex/oct> <bin/dec/hex/oct>',
|
|
aliases: ['convertnumbers', 'cvnums'],
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'convertseconds',
|
|
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'],
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'converttime',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
const str = msg.text.split(' ').slice(1).join(' ');
|
|
|
|
if (!str) {
|
|
msg.resolve('Invalid input');
|
|
return true;
|
|
}
|
|
|
|
msg.resolve(parseTimeToSeconds(str), 'seconds');
|
|
return true;
|
|
},
|
|
description: 'Convert ywdhms to seconds.',
|
|
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> => {
|
|
const str = msg.text.split(' ').slice(1).join(' ');
|
|
|
|
if (!str) {
|
|
msg.resolve('Invalid input');
|
|
return true;
|
|
}
|
|
|
|
const sec = parseTimeToSeconds(str);
|
|
msg.resolve(readableTime(sec));
|
|
|
|
return true;
|
|
},
|
|
aliases: ['rcvt'],
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'eval',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
if (!simplified[0]) {
|
|
return true;
|
|
}
|
|
|
|
const wholeRow = msg.text.split(' ').slice(1).join(' ');
|
|
|
|
try {
|
|
const repl = await opMath(wholeRow);
|
|
msg.resolve(repl);
|
|
} catch (e: any) {
|
|
msg.resolve('Could not evaluate expression:', e.message);
|
|
}
|
|
|
|
return true;
|
|
},
|
|
aliases: ['math', 'calc'],
|
|
usage: '<expression>',
|
|
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> => {
|
|
msg.resolve('Your userId is %s.', msg.fullSenderID);
|
|
return true;
|
|
},
|
|
description: 'Display your userId (internal user identification)',
|
|
hidden: true,
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'roomid',
|
|
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,
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'serverid',
|
|
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.'
|
|
);
|
|
|
|
return true;
|
|
},
|
|
description: 'Display the internal identification of this room',
|
|
hidden: true,
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'rgb2hex',
|
|
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
|
|
);
|
|
if (!channels || channels[2] == null) {
|
|
msg.resolve('Invalid parameter');
|
|
return true;
|
|
}
|
|
|
|
const r = parseInt(channels[2], 10);
|
|
const g = parseInt(channels[3], 10);
|
|
const b = parseInt(channels[4], 10);
|
|
|
|
if (r > 255 || g > 255 || b > 255) {
|
|
msg.resolve('Invalid colors');
|
|
return true;
|
|
}
|
|
|
|
msg.resolve(rgbToHex(r, g, b));
|
|
return true;
|
|
},
|
|
description: 'Convert RGB to HEX colors',
|
|
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> => {
|
|
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
|
|
);
|
|
if (!channels || channels[2] == null) {
|
|
msg.resolve('Invalid parameter');
|
|
return true;
|
|
}
|
|
|
|
const r = parseInt(channels[2], 10);
|
|
const g = parseInt(channels[3], 10);
|
|
const b = parseInt(channels[4], 10);
|
|
|
|
if (r > 255 || g > 255 || b > 255) {
|
|
msg.resolve('Invalid colors');
|
|
return true;
|
|
}
|
|
const hsl = RGBToHSL(r, g, b);
|
|
|
|
msg.resolve('hsl(%d, %d%, %d%)', hsl.h, hsl.s, hsl.l);
|
|
return true;
|
|
},
|
|
description: 'Convert RGB to HSL colors',
|
|
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> => {
|
|
if (!simplified[0]) {
|
|
return true;
|
|
}
|
|
let hexcode = simplified[0];
|
|
|
|
if (hexcode.indexOf('#') === -1) {
|
|
hexcode = '#' + hexcode;
|
|
}
|
|
|
|
if (hexcode.length !== 4 && hexcode.length !== 7) {
|
|
msg.resolve('Invalid length');
|
|
return true;
|
|
}
|
|
|
|
const rgb = hexToRgb(hexcode);
|
|
if (!rgb) {
|
|
msg.resolve('Invalid HEX notation');
|
|
return true;
|
|
}
|
|
|
|
msg.resolve('rgb(%d, %d, %d)', rgb.r, rgb.g, rgb.b);
|
|
return true;
|
|
},
|
|
description: 'Convert HEX to RGB colors',
|
|
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> => {
|
|
if (!simplified[0]) {
|
|
msg.resolve('Please specify host name!');
|
|
return true;
|
|
}
|
|
if (!simplified[1]) {
|
|
msg.resolve('Please specify port!');
|
|
return true;
|
|
}
|
|
|
|
const host = simplified[0];
|
|
const port = parseInt(simplified[1], 10);
|
|
|
|
if (isNaN(port) || port <= 0 || port > 65535) {
|
|
msg.resolve('Invalid port number!');
|
|
return true;
|
|
}
|
|
|
|
let statusString = msg.source.format.format('bold', 'closed');
|
|
let status;
|
|
|
|
try {
|
|
status = await pingTcpServer(host, port);
|
|
statusString = msg.source.format.format('bold', 'open');
|
|
} catch (e: any) {
|
|
status = e.message;
|
|
}
|
|
|
|
if (!isNaN(parseFloat(status))) {
|
|
status = status + ' ms';
|
|
}
|
|
|
|
msg.resolve(`Port ${port} on ${host} is ${statusString} (${status})`);
|
|
return true;
|
|
},
|
|
description: 'Ping a host',
|
|
usage: '<host> <port>',
|
|
aliases: ['tcpup', 'tping'],
|
|
hidden: true,
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'convert',
|
|
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!');
|
|
return true;
|
|
}
|
|
|
|
let src = simplified[1];
|
|
let dst = simplified[2];
|
|
if (dst && dst.toLowerCase() === 'to') {
|
|
dst = simplified[3];
|
|
}
|
|
|
|
if (!src) {
|
|
msg.resolve('Please specify source unit!');
|
|
return true;
|
|
}
|
|
|
|
if (!dst) {
|
|
msg.resolve('Please specify destination unit!');
|
|
return true;
|
|
}
|
|
|
|
let res = null;
|
|
src = getUnitAbbreviation(src);
|
|
dst = getUnitAbbreviation(dst);
|
|
|
|
if (!src) {
|
|
msg.resolve('Source unit not found!');
|
|
return true;
|
|
}
|
|
|
|
if (!dst) {
|
|
msg.resolve('Destination unit not found!');
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
res = convert(tqnt).from(src).to(dst);
|
|
} catch (e) {
|
|
res = null;
|
|
}
|
|
|
|
if (res) {
|
|
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;
|
|
|
|
msg.resolve(` ${tqnt} ${bsrcdesc} => ${res} ${bdstdesc}`);
|
|
return true;
|
|
}
|
|
|
|
msg.resolve('Failed to convert.');
|
|
return true;
|
|
},
|
|
description: 'Convert between quantities in different units.',
|
|
usage: '<number> <from unit> <to unit>',
|
|
aliases: ['cv', 'unit'],
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'currency',
|
|
execute: async (
|
|
msg: IMessage,
|
|
msr: MessageResolver,
|
|
spec: any,
|
|
prefix: string,
|
|
...simplified: any[]
|
|
): Promise<boolean> => {
|
|
let cexData: CEXResponse | null = plugin.cexCache.cache as CEXResponse;
|
|
const currentStamp = new Date().toISOString().replace(/T(.*)$/, '');
|
|
if (plugin.cexCache.expiry < Date.now()) {
|
|
let fetched;
|
|
try {
|
|
const data = await httpGET(`https://api.exchangerate.host/latest?v=${currentStamp}`);
|
|
fetched = JSON.parse(data);
|
|
logger.log('[utility] Fetched currency exchange rates successfully.');
|
|
} catch (e) {
|
|
fetched = null;
|
|
}
|
|
|
|
if (!fetched?.rates) {
|
|
msg.resolve(
|
|
'Could not fetch currency exchange rates at this time. Please try again later.'
|
|
);
|
|
return true;
|
|
}
|
|
|
|
Object.assign(plugin.cexCache, {
|
|
cache: fetched.rates,
|
|
date: fetched.date,
|
|
expiry: Date.now() + 86400000 / 2 // half-day
|
|
});
|
|
|
|
cexData = fetched.rates as CEXResponse;
|
|
}
|
|
|
|
if (simplified[0] === '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: %s',
|
|
Object.keys(cexData).join(', ')
|
|
);
|
|
return true;
|
|
}
|
|
|
|
const inputValue = parseFloat(simplified[0]);
|
|
let fromCurrency = simplified[1];
|
|
let toCurrency = simplified[2];
|
|
if (isNaN(inputValue) || !fromCurrency || !toCurrency) {
|
|
msg.resolve('Invalid parameters.');
|
|
return true;
|
|
}
|
|
|
|
fromCurrency = fromCurrency.toUpperCase();
|
|
toCurrency = toCurrency.toUpperCase();
|
|
|
|
if (fromCurrency !== 'EUR' && !cexData[fromCurrency]) {
|
|
msg.resolve('This currency is currently not supported.');
|
|
return true;
|
|
}
|
|
|
|
if (toCurrency !== 'EUR' && !cexData[toCurrency]) {
|
|
msg.resolve('This currency is currently not supported.');
|
|
return true;
|
|
}
|
|
|
|
if (fromCurrency === toCurrency) {
|
|
msg.resolve('%f %s', inputValue, fromCurrency);
|
|
return true;
|
|
}
|
|
|
|
const resultValue = ((cexData[toCurrency] * inputValue) / cexData[fromCurrency]).toFixed(4);
|
|
const conversionRate = (cexData[toCurrency] / cexData[fromCurrency]).toFixed(4);
|
|
const conversionRateString = inputValue !== 1 ? `(1 = ${conversionRate})` : '';
|
|
|
|
msg.resolve(`${inputValue} ${fromCurrency} => ${resultValue} ${toCurrency} ${conversionRateString}`);
|
|
return true;
|
|
},
|
|
description: 'Convert between currencies.',
|
|
usage: '<number> | [date | list] [<from currency>] [<to currency>]',
|
|
aliases: ['cex', 'exchange'],
|
|
});
|
|
|
|
cmds.push({
|
|
name: 'randomnumber',
|
|
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;
|
|
}
|
|
|
|
let min = parseInt(simplified[0], 10);
|
|
let max = parseInt(simplified[1], 10);
|
|
let count = parseInt(simplified[2], 10);
|
|
const countMax = plugin.config.config.randomMax || 64;
|
|
if (isNaN(min) || isNaN(max)) {
|
|
msg.resolve('Invalid numbers.');
|
|
return true;
|
|
}
|
|
if (min > max) {
|
|
const realMax = min + 0;
|
|
min = max;
|
|
max = realMax;
|
|
}
|
|
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;
|
|
}
|
|
if (count > countMax) {
|
|
msg.resolve('Too many to generate. Maximum: ' + countMax);
|
|
return true;
|
|
}
|
|
const numbers = [];
|
|
for (let i = 0; i < count; i++) {
|
|
numbers.push(Math.floor(Math.random() * (max - min + 1)) + min);
|
|
}
|
|
msg.resolve(numbers.join(' '));
|
|
return true;
|
|
},
|
|
description: 'Generate a random number between <min> and <max>.',
|
|
usage: '<min> <max> [<count>]',
|
|
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> => {
|
|
console.log(simplified);
|
|
msg.resolve(
|
|
`argument 1: '${simplified[0]}' argument 2: '${simplified[1]}'`
|
|
);
|
|
return true;
|
|
},
|
|
description: 'Test the command argument parser',
|
|
usage: '',
|
|
hidden: true,
|
|
});
|
|
|
|
commands.registerCommand(
|
|
cmds.map((x: any) => {
|
|
x.plugin = plugin.manifest.name;
|
|
return x;
|
|
})
|
|
);
|
|
}
|
|
|
|
@Configurable({
|
|
ipfsGateway: 'https://ipfs.io',
|
|
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);
|
|
}
|
|
|
|
@EventListener('pluginUnload')
|
|
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);
|
|
}
|
|
}
|
|
|
|
initialize(): void {
|
|
this.on('message', (msg: IMessage) => {
|
|
// Pre-regex check
|
|
if (msg.text.indexOf('ipfs://') === -1 && msg.text.indexOf('Qm') === -1) {
|
|
return;
|
|
}
|
|
|
|
// IPFS urlify
|
|
const mmatch = msg.text.match(/(?:ipfs:\/\/|\s|^)(Qm[\w\d]{44})(?:\s|$)/);
|
|
if (mmatch && mmatch[1]) {
|
|
msg.resolve(this.config.config.ipfsGateway + '/ipfs/' + mmatch[1]);
|
|
}
|
|
});
|
|
|
|
// Initialize list of units
|
|
createUnitIndex();
|
|
}
|
|
}
|
|
|
|
module.exports = UtilityPlugin;
|