Вместо вызова двух middleware вызывается один дважды
Если вы не знакомы с telegraf, middleware в нём работают точно так же, как в Express.
У меня есть бот на telegraf. Для него я написал два модуля PollManager и CommandManager - это классы. Я хочу их подключать через bot.use(...). Для этого пришлось написать две middleware-обёртки.
Ниже приведён код. Суть его вкратце: в модуле экпортируется функция, которая создаёт экземпляр класса и возвращает результат второй функции, которая создаёт middleware с привязанным к ней экземляром класса.
Это у меня реализовано на основе работы стрелочных функций, который перенимают контекст из внешнего кода.
Но получается совсем погано: мало того, что вместо двух middleware вызывается один и дважды, так ещё и manager у него меняется (чего быть не должно). Это можно проверить через console.log.
index.js
const Telegraf = require('telegraf')
const PollManager = require('./poll_manager')
const CommandManager = require('./command_manager')
const bot = new Telegraf("1075485707:AAGBLq-WgMoGaJAmpJK9Y4JEtW8IVbDpt_U")
bot.use(CommandManager('./commands'))
bot.use(PollManager('./polls'))
bot.launch(console.log("bot start"))
command_manager.js
//Makes CommandManager and return middleware configured to work with this manager.
module.exports = (path) => {
let manager = new CommandManager(path);
return middleware(manager);
}
/// Listens commands and giving it to the manager to execute.
middleware = (manager) => {
return (ctx, next) => {
///Message handling part
if(ctx.updateType === 'message' && ctx.updateSubTypes.includes('text')) {
if(ctx.message.text.startsWith('/')) {
let text = ctx.message.text;
let command = text.split(' ')[0].slice(1);
console.log("Command_manager: " + command);
if(manager.isCommandExist(command)) {
manager.execute(command, ctx);
}
}
}
next();
}
}
class CommandManager { ... }
poll_manager.js
//Makes PollManager and return middleware configured to work with this manager.
module.exports = (path) => {
let manager = new PollManager(path);
return middleware(manager);
}
/// Gives poll updates information to mager
/// And listens commands and giving it to the manager to execute.
middleware = (manager) => {
return (ctx, next) => {
///Message handling part
if(ctx.updateType === 'message' && ctx.updateSubTypes.includes('text')) {
if(ctx.message.text.startsWith('/')) {
let text = ctx.message.text;
let command = text.split(' ')[0].slice(1);
console.log("Poll_manager: " + command);
if(manager.isCommandExist(command)) {
manager.executePoll(command, ctx);
}
}
}
///Vote updates handling part
if(ctx.updateType === 'poll') {
manager.handlePollUpdate(ctx);
}
next();
}
}
PollManager = class { ... }
Ответы (1 шт):
Я понял, в чём ошибка!
По умолчанию, если не написать директиву let, переменная объявляется глобально. И в одном модуле, и в другом я объявлял функцию middleware, которая создавала middleware с привязанным нужным manager (для этого я использовал стрелочные функции и принципы их работы с контекстом).
В итоге, когда я импортировал оба модуля поочерёдно, одна глобальная функция middleware перетирала собой другую. Что приводило к тому, что у меня использовался только один middleware, но как два разных.
Вывод: не полениться и настроить eslint - очень хорошая идея.