You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
5.6 KiB
159 lines
5.6 KiB
let { logger } = require('./logging');
|
|
let { modules } = require('./module/index');
|
|
let trie = require('trie-prefix-tree');
|
|
let { getShortestPrefix } = require('./utility');
|
|
let help = require('./module/help');
|
|
let message = require('./message');
|
|
let utility = require('./utility');
|
|
let { initModule } = require('./module/abstract');
|
|
let { sanitizeConfig } = require('./config');
|
|
|
|
let commandPrefix = '!';
|
|
|
|
class Engine {
|
|
constructor(config, bot, modules) {
|
|
this.config = config;
|
|
this.bot = bot;
|
|
this.modules = modules;
|
|
this.moduleMap = new Map();
|
|
this.commands = [];
|
|
this.commandMap = new Map();
|
|
this.commandRadixTree = trie([]);
|
|
}
|
|
|
|
initModules() {
|
|
let sanitizedGlobalConfig = sanitizeConfig(
|
|
this.config,
|
|
[
|
|
'userPassword',
|
|
'accessToken'
|
|
])
|
|
|
|
this.modules.forEach((mod) => {
|
|
logger.info("Loading module: %s", mod.name);
|
|
initModule(mod, sanitizedGlobalConfig);
|
|
logger.info("Recognized commands: %s", mod.getRecognizedCommands())
|
|
this.moduleMap.set(mod.command, mod);
|
|
this.commandMap.set(mod.command, mod);
|
|
this.commandRadixTree.addWord(mod.command);
|
|
});
|
|
|
|
this.modules.forEach((mod) => {
|
|
let shortCharCommand = getShortestPrefix(this.commandRadixTree, mod.command, 1);
|
|
let short3CharCommand = getShortestPrefix(this.commandRadixTree, mod.command, 3);
|
|
let shortCommandAliases = [shortCharCommand, short3CharCommand];
|
|
logger.info("Adding short command %s for module: %s", shortCommandAliases, mod.name);
|
|
shortCommandAliases.forEach((commandAlias) => {
|
|
this.commandMap.set(commandAlias, mod);
|
|
})
|
|
});
|
|
|
|
this.helpModule = help.create(this.moduleMap)
|
|
initModule(this.helpModule);
|
|
this.moduleMap.set(this.helpModule.command, this.helpModule);
|
|
this.commandMap.set('help', this.helpModule);
|
|
this.commands = Array.from(this.commandMap.keys()).sort()
|
|
|
|
logger.info("Bound modules to keywords: %o", this.moduleMap);
|
|
}
|
|
|
|
init() {
|
|
logger.info("Initializing modules");
|
|
this.initModules();
|
|
|
|
/* Bind Message Parsing */
|
|
let engine = this;
|
|
let handleEvent = (event, room, toStartOfTimeline) => {
|
|
/* Don't process messages from self */
|
|
if (event.sender.userId !== this.config.userId) {
|
|
/* don't process messages that aren't of type m.room.message */
|
|
if (event.getType() !== "m.room.message") {
|
|
logger.debug("Recieved message of type: %s", event.getType());
|
|
return;
|
|
} else {
|
|
let messageBody = event.event.content.body;
|
|
logger.debug("[%s] %s", room.name, messageBody);
|
|
if (messageBody.indexOf(commandPrefix) === 0) {
|
|
let command = messageBody.split(' ')[0].substring(1);
|
|
if (engine.commandMap.has(command)) {
|
|
engine.commandMap.get(command).handleMessage(event, room, sendResponseMessageCallback(engine.bot));
|
|
} else {
|
|
let responseMessage = "The following commands are recognized"
|
|
responseMessage += "\n" + engine.commands.join(", ")
|
|
responseMessage += "\nAdditional information can be discovered with !help <command>"
|
|
sendResponseMessage(engine.bot, room, responseMessage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.bot.init(handleEvent);
|
|
|
|
/* Capture Exit Conditions */
|
|
|
|
["SIGINT", "SIGTERM"].forEach((signature) => {
|
|
process.on(signature, async () => {
|
|
await this.bot.sendStatusShutdown()
|
|
.then(() => {
|
|
logger.info("Gracefully stopping Matrix SDK Client")
|
|
this.bot.client.stopClient();
|
|
});
|
|
process.exit(0);
|
|
});
|
|
});
|
|
|
|
process.on('exit', () => {
|
|
logger.info("Shutting Down");
|
|
});
|
|
|
|
return this;
|
|
}
|
|
|
|
run() {
|
|
this.bot.connect();
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle the callback sending messages via the bot
|
|
*
|
|
* @param {*} bot
|
|
* @param {*} room
|
|
* @param {*} responseMessage
|
|
*/
|
|
function sendResponseMessage(bot, room, responseMessage) {
|
|
logger.debug("Responding to room: %s with %o", room.roomId, responseMessage);
|
|
Promise.resolve(responseMessage).then((promisedMessage) => {
|
|
if (responseMessage !== null) {
|
|
logger.debug("Sending message: %s", promisedMessage);
|
|
if (promisedMessage instanceof Object) {
|
|
bot.client.sendMessage(room.roomId, promisedMessage);
|
|
} else if (utility.isString(promisedMessage)) {
|
|
bot.client.sendMessage(room.roomId, message.createBasic(promisedMessage));
|
|
} else {
|
|
logger.error("Unable to process response message: %s", promisedMessage);
|
|
}
|
|
} else {
|
|
logger.warn("No response message offered");
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Wrapper to produce a callback function that can be passed to the modules
|
|
*
|
|
* @param {*} bot
|
|
*/
|
|
function sendResponseMessageCallback(bot) {
|
|
return (room, responseMessage) => {
|
|
sendResponseMessage(bot, room, responseMessage);
|
|
}
|
|
}
|
|
|
|
function create(config, bot) {
|
|
return new Engine(config, bot, modules)
|
|
}
|
|
|
|
exports.create = create;
|