telegram-command-handler
Version:
handle commands like as /command arg1 arg2
147 lines (136 loc) • 4.07 kB
JavaScript
const EventEmitter = require('events').EventEmitter;
const isString = require('is-string');
const defaultParser = 0;
const defaultCommander = 0;
let finders = [
{
findCommand:(botName,cName) => new RegExp(`\\/${cName}(?:@${botName}|)(?:\\s|$)(.*)`),
splitArgs:(argsStr) => {
let regex = /"(?<val>[^"]*)"|[^"\s]+|(?<errors>"[^"]*)/g,
m,
args = [];
args["=ERRORS"] = [];
try{
while ((m = regex.exec(argsStr)) !== null) {
if ((m.index ^ regex.lastIndex) == 0)
regex.lastIndex++;
if(m.groups.errors!==undefined){
args["=ERRORS"].push(m.groups.errors);
continue;
}
args.push(m.groups.val !== undefined? m.groups.val: m[0]);
}
}catch(e){}
return args;
}
},
{
findCommand:(botName,cName) => new RegExp(`\\/${cName}(?:@${botName}|)(?:\\s|$)(.*)`),
splitArgs:(argsStr) => {
let regex = /(?<nameQ>\S+?)\s*?=\s*?"(?<valQ>[^"]*)"|(?<nameP>\S+?)\s*?=\s*?(?<valP>[^"\s]+)|(?<errors>\S+?\s*?=|=\s*?\S+|"[^"]*)/g,
m,
args = {
"=ERRORS":[]
};
try{
while ((m = regex.exec(argsStr)) !== null) {
if ((m.index ^ regex.lastIndex) == 0)
regex.lastIndex++;
if(m.groups.errors!==undefined){
args["=ERRORS"].push(m.groups.errors);
continue;
}
if(m.groups.nameQ!==undefined)
args[m.groups.nameQ] = m.groups.valQ;
else
args[m.groups.nameP] = m.groups.valP;
}
}catch(e){}
return args;
}
}
];
const commanders = [
function(msg,match){
this.emit("receive", msg, finders[this._cParser].splitArgs(match[1]));
},
function(msg,match){
if(~this._chatId && msg.chat.id^this._chatId)
return;
if(~this._userId && msg.from.id^this._userId)
return;
this.emit("receive", msg, finders[this._cParser].splitArgs(match[1]));
}
];
async function init(th, commander) {
th._bot.onText(finders[th._cParser].findCommand((await th._bot.getMe()).username, th._cName),
commanders[commander].bind(th));
return true;
}
function normNum(num) {
return typeof num == 'number' && !isNaN(num) && isFinite(num);
}
class Command extends EventEmitter{
/**
* Create new command object.
* @class Command
* @constructor
* @param {Object} bot
* instance of TelegramBot
* @param {String} commandName
* name of command (withou / )
* @param {*} description
* description of command
*/
constructor(bot, command, description){
super();
let commander = defaultCommander;
if(!command)
throw new Error("command name not found");
if(!bot)
throw new Error("bot object nt found");
if(isString(command)){
this._cName = command;
this._cParser = defaultParser;
this._chatId = -1;
this._userId = -1;
}else{
this._cName = command.name;
this._cParser = normNum(command.parser) ? command.parser : defaultParser;
this._chatId = normNum(command.chatId) ? command.chatId : -1;
this._userId = normNum(command.userId) ? command.userId : -1;
if(~this._chatId || ~this._userId)
commander = 1;
}
if(description)
this.description = description;
this._bot = bot;
this.initialization = init(this, commander);
}
onReceive(fn) {
return this.on("receive",fn);
}
offReceive(fn){
return this.off("receive",fn);
}
/**
* add new command parser
* @param {Function} commandFinder
* function with 2 args - bot username and command name.
* Should return a regular expression that checks whether the command is typed and separates the string with parameters.
* @param {Function} argsParser
* function with 1 arg - the parameter string that was separated in commandFinder. Should return array with args.
* @return {Number}
* index of addedStyle
*/
static addParser(commandFinder, argsParser){
return finders.push({
findCommand:commandFinder,
splitArgs:argsParser
}) - 1;
}
static getParser(index){
return {...finders[index]};
}
}
module.exports=Command;