testing a message resolver

This commit is contained in:
Evert Prants 2020-12-13 12:16:05 +02:00
parent 753e021941
commit b1d4978024
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
5 changed files with 112 additions and 4 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@squeebot/core",
"version": "3.0.1",
"version": "3.1.0",
"description": "Squeebot v3 core for the execution environment",
"main": "lib/index.js",
"module": "lib/",

View File

@ -1,5 +1,5 @@
import { IPlugin } from '../plugin';
import { IMessage, Protocol } from '../types';
import { IMessage, MessageResolver, Protocol } from '../types';
import { ScopedEventEmitter } from '../util/events';
export interface IChannel {
@ -32,20 +32,28 @@ export class ChannelManager {
for (const event of ['message', 'event', 'special']) {
this.stream.on('channel', event, (data: IMessage) => {
let msr;
if (event === 'message') {
msr = new MessageResolver(data);
}
const plugin = ChannelManager.determinePlugin(data.source);
if (!plugin) {
return;
}
const source = plugin.manifest.name;
const emitTo = this.getChannelsByPluginName(source, data.source);
for (const chan of emitTo) {
if (chan.plugins.length < 2) {
continue;
}
for (const pl of chan.plugins) {
if (pl !== source &&
!(pl.indexOf('/') !== -1 && pl.split('/')[0] === source)) {
this.stream.emitTo(pl, event, data, chan);
this.stream.emitTo(pl, event, data, chan, msr);
}
}
}

View File

@ -5,3 +5,4 @@ export * from './message';
export * from './message-format';
export * from './protocol';
export * from './service';
export * from './staged-handler';

View File

@ -85,7 +85,12 @@ export interface IMessage {
* @param args Message data
*/
resolve(...args: any[]): void;
/**
* Bot's error response to this message. Will be passed to the protocol,
* which usually sends `error.message` directly to the target of the message
* @param error Error
*/
reject(error: Error): void;
/**
* Insert a mention into the response
* @param target UserTarget to mention (i.e. `msg.sender`)

View File

@ -0,0 +1,94 @@
import { IMessage } from './message';
/**
* Message data object for staged handling
* Response value is always mandatory.
*/
export interface IMessageData {
text?: string;
data?: any;
compose?: any[];
value: any;
}
export type IMessageHandler = (data: IMessageData | string, reject: Function, next: IMessageHandler) => void;
/**
* Staged messaging handler
*/
export class MessageResolver {
private handlers: IMessageHandler[] = [];
public static textFormatter(text: string | undefined, value: any): string {
let stri = text || '';
if (Array.isArray(value) || typeof value === 'object') {
stri = stri.replace(/%([a-z]+)?(\d+)?/ig, (substr: string, word?: string, nr?: number): string => {
if (nr && typeof nr === 'string') {
nr = parseInt(nr as 'string', 10);
}
if (Array.isArray(value) && nr != null) {
return value[nr];
}
if (!word) {
return substr;
}
const val = value[word];
if (Array.isArray(val) && nr) {
return val[nr];
}
return val;
});
} else if (value === 'string') {
if (!text) {
stri = value;
} else {
text += ' ' + value;
}
}
return stri;
}
constructor(public msg: IMessage) {}
/**
* Inject a middleware message handler
* @param fn Message handler function
*/
use(fn: IMessageHandler): void {
this.handlers.push(fn);
}
/**
* Resolve the message. Call this only from the last plugin in the chain.
* @param data Message response data
*/
resolve(data: IMessageData | string, ...rest: any[]): void {
const ist = this.handlers.pop();
if (!this.handlers.length || !ist) {
if (typeof data === 'string') {
this.msg.resolve(data, ...rest);
return;
}
if (data.compose && Array.isArray(data.compose)) {
this.msg.resolve(data.compose);
return;
}
this.msg.resolve(MessageResolver.textFormatter(data.text, data.value));
return;
}
ist.call(this, data, this.msg.reject, this.resolve);
}
/**
* Reject the message. You can call this from anywhere.
* @param error Error
*/
reject(error: Error): void {
this.msg.reject(error);
}
}