concierge-bot
Version:
Extensible general purpose chat bot.
123 lines (113 loc) • 4.43 kB
JavaScript
/**
* A special API wrapper for allowing loopback/pipe events to occur.
*
* Written By:
* Matthew Knox
*
* License:
* MIT License. All code unless otherwise specified is
* Copyright (c) Matthew Knox and Contributors 2017.
*/
let platform;
class LoopbackApi {
constructor(baseApi, loopMaxDepth, pipeEvents) {
this._baseApi = baseApi;
this._copyApiMethods();
this._loopMaxDepth = loopMaxDepth;
this._pipeEvents = pipeEvents;
}
/**
* Gets the loopback API/event for a received message.
* @param {IntegrationApi} api the api to use when sending messages.
* @param {Object} event the event object.
* @returns {Object} an object representing the api and event that should be used
*/
static getLoopbackApi(api, event) {
if (api instanceof LoopbackApi) {
return {
api: api,
event: event
};
}
const currConfig = platform.config.getSystemConfig('loopback');
const pipeEvents = [];
if (currConfig.pipe !== false && event.body.contains('|')) {
const newBodies = event.body.split(/\s*\|\s*/g);
for (let n of newBodies) {
const e = shim.createEvent(event.thread_id, event.sender_id, event.sender_name, n);
e.event_source = event.event_source;
pipeEvents.push(e);
}
}
const loopDepth = currConfig.enabled ? currConfig.maxDepth || platform.loopDepth || 0 : 0;
return {
api: pipeEvents.length > 1 || loopDepth > 0 ? new LoopbackApi(api, loopDepth, pipeEvents.slice(1)) : api,
event: pipeEvents[0] || event
};
}
_getClassKeys(obj) {
const ret = new Set();
const methods = obj => {
if (obj !== Object.prototype) {
const ps = Object.getOwnPropertyNames(obj);
for (let p of ps) {
ret.add(p);
}
methods(Object.getPrototypeOf(obj));
}
};
methods(obj.__proto__);
return Array.from(ret);
}
_copyApiMethods() {
for (let key of this._getClassKeys(this._baseApi).concat(Object.keys(this._baseApi))) {
if (!this[key]) {
this[key] = typeof (this._baseApi[key]) === 'function' ?
this._baseApi[key].bind(this._baseApi) :
this._baseApi[key];
}
}
}
_loopback(message, thread) {
if (this._pipeEvents.length === 0 && this._loopMaxDepth <= 0) {
return;
}
process.nextTick(() => {
let api;
const event = shim.createEvent(thread, this._pipeEvents[0].sender_id, this._pipeEvents[0].sender_name, message);
if (this._pipeEvents.length > 0) {
api = new LoopbackApi(this._baseApi, this._loopMaxDepth, this._pipeEvents.slice(1));
event.event_source = this._pipeEvents[0].event_source;
event.body = `${this._pipeEvents[0].body} ${event.body}`;
event.arguments = this._pipeEvents[0].arguments.concat(event.arguments);
event.arguments_body = event.body.substr(event.arguments[0].length + 1);
}
else {
api = new LoopbackApi(this._baseApi, this._loopMaxDepth - 1, []);
event.event_source = 'loopback';
}
platform.onMessage(api, event);
});
}
sendMessage(message, thread) {
this._loopback(message, thread);
if (this._pipeEvents.length === 0) {
return this._baseApi.sendMessage(message, thread);
}
}
sendUrl(url, thread) {
this._loopback(url, thread);
if (this._pipeEvents.length === 0) {
return this._baseApi.sendUrl(url, thread);
}
}
}
/**
* Initialise this loopback builder.
* @param {Platform} plat the platform to pass messages to.
* @returns {function()} a method that will replace each api/event with its loopback equivilant if needed
*/
module.exports = plat => { // avoid using globals
platform = plat;
return (api, event) => LoopbackApi.getLoopbackApi(api, event);
};