fix keyword matcher, implement channel verification

This commit is contained in:
Evert Prants 2020-12-05 13:22:37 +02:00
parent d11f697dec
commit 0856bcb0fe
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
1 changed files with 46 additions and 15 deletions

View File

@ -11,8 +11,9 @@ import { EMessageType, IMessage, IMessageTarget } from '@squeebot/core/lib/types
import { fullIDMatcher } from '@squeebot/core/lib/common';
import { logger } from '@squeebot/core/lib/core';
import { IChannel } from '@squeebot/core/lib/channel';
declare type Matcher = (msg: IMessage) => boolean;
declare type Matcher = (msg: IMessage) => any;
interface CommandSpec {
name: string;
@ -26,6 +27,7 @@ interface CommandSpec {
match?: string | Matcher;
hidden?: boolean;
permissions?: string[];
tempargv?: any[];
execute(msg: IMessage, command: CommandSpec, prefix: string, ...args: any[]): Promise<boolean>;
}
@ -48,6 +50,7 @@ const rates: {[key: string]: Rate} = {};
},
keywords: ['squeebot'],
rateLimits: [],
channelMatching: false,
})
class SqueebotCommandsAPIPlugin extends Plugin {
private commands: CommandSpec[] = [];
@ -153,8 +156,8 @@ class SqueebotCommandsAPIPlugin extends Plugin {
return permitted;
}
public async handlePrefix(msg: IMessage, prefix: string): Promise<void> {
const text = msg.data.text ? msg.data.text : msg.data;
public async handlePrefix(msg: IMessage, prefix: string, plugins: string[]): Promise<void> {
const text = msg.text;
const separate = text.split(' ');
if (separate[0].indexOf(prefix) === 0) {
separate[0] = separate[0].substring(prefix.length);
@ -163,6 +166,10 @@ class SqueebotCommandsAPIPlugin extends Plugin {
// Iteration 1: Resolve commands by name and by aliases
const withAliases = [];
for (const spec of this.commands) {
if (plugins.length && plugins.indexOf(spec.plugin) === -1) {
continue;
}
if (spec.aliases && spec.aliases.indexOf(separate[0]) !== -1) {
const copy = Object.assign({}, spec);
copy.alias = spec.name;
@ -208,6 +215,12 @@ class SqueebotCommandsAPIPlugin extends Plugin {
// Start executing
for (const spec of permitted) {
// Help command needs access to plugin list in the channel
// Very dirty
if (spec.name === 'help') {
spec.tempargv = plugins;
}
const success = await spec.execute(msg, spec, prefix, ...separate.slice(1));
if (success) {
break;
@ -217,8 +230,8 @@ class SqueebotCommandsAPIPlugin extends Plugin {
// Done
}
public async handleKeywords(msg: IMessage, keyword: string): Promise<void> {
const text = msg.data.text ? msg.data.text : msg.data;
public async handleKeywords(msg: IMessage, keyword: string, plugins: string[]): Promise<void> {
const text = msg.text.toLowerCase();
// Only pass command specs which have `match` and match rooms
let matching = [];
@ -227,16 +240,24 @@ class SqueebotCommandsAPIPlugin extends Plugin {
continue;
}
if (plugins.length && plugins.indexOf(spec.plugin) === -1) {
continue;
}
if (typeof spec.match === 'function') {
try {
if (!spec.match(msg)) {
const match = spec.match(msg);
if (match == null) {
continue;
}
spec.tempargv = match;
} catch (e) {}
} else {
if (!text.match(spec.match)) {
const rgx = text.match(spec.match);
if (rgx == null) {
continue;
}
spec.tempargv = rgx.slice(1);
}
matching.push(spec);
@ -272,7 +293,8 @@ class SqueebotCommandsAPIPlugin extends Plugin {
// Start executing
for (const spec of permitted) {
const success = await spec.execute(msg, spec, keyword);
const success = await spec.execute(msg, spec, keyword,
...(spec.tempargv ? spec.tempargv : []));
if (success) {
break;
}
@ -282,20 +304,25 @@ class SqueebotCommandsAPIPlugin extends Plugin {
}
@EventListener('message')
public digest(msg: IMessage): void {
public digest(msg: IMessage, chan: IChannel): void {
if (msg.type !== EMessageType.message) {
return;
}
let allowedPlugins: string[] = [];
if (chan && this.config.get('channelMatching', false) === true) {
allowedPlugins = chan.plugins;
}
const text = msg.data.text ? msg.data.text : msg.data;
const prefixes = this.config.config.prefix;
const keywords = this.config.config.keywords;
// Attempt to match keywords
if (!keywords && !keywords.length) {
if (keywords && keywords.length) {
for (const kw of keywords) {
if (text.match(kw)) {
this.handleKeywords(msg, kw).catch(e =>
if (text.toLowerCase().match(kw) != null) {
this.handleKeywords(msg, kw, allowedPlugins).catch(e =>
logger.error('[%s] Command handler threw an error:', this.name, e.stack));
return;
}
@ -329,7 +356,7 @@ class SqueebotCommandsAPIPlugin extends Plugin {
return;
}
this.handlePrefix(msg, prefix).catch(e =>
this.handlePrefix(msg, prefix, allowedPlugins).catch(e =>
logger.error('[%s] Command handler threw an error:', this.name, e.stack));
}
@ -389,10 +416,14 @@ class SqueebotCommandsAPIPlugin extends Plugin {
}
}
private helpCommand(msg: IMessage, prefix: string): void {
private helpCommand(msg: IMessage, prefix: string, plugins: string[]): void {
// Iteration 1: Resolve commands by name and by aliases
const withAliases = [];
for (const spec of this.commands) {
if (plugins.length && plugins.indexOf(spec.plugin) === -1) {
continue;
}
if (spec.aliases && spec.aliases.length) {
for (const alias of spec.aliases) {
const copy = Object.assign({}, spec);
@ -462,7 +493,7 @@ class SqueebotCommandsAPIPlugin extends Plugin {
usage: '[<command>]',
description: 'Show command usage or list all commands',
execute: async (msg: IMessage, spec: CommandSpec, prefix: string): Promise<boolean> => {
this.helpCommand(msg, prefix);
this.helpCommand(msg, prefix, spec.tempargv as string[]);
return true;
}
});