Вместо вызова двух 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 шт):

Автор решения: witaway

Я понял, в чём ошибка!

По умолчанию, если не написать директиву let, переменная объявляется глобально. И в одном модуле, и в другом я объявлял функцию middleware, которая создавала middleware с привязанным нужным manager (для этого я использовал стрелочные функции и принципы их работы с контекстом).

В итоге, когда я импортировал оба модуля поочерёдно, одна глобальная функция middleware перетирала собой другую. Что приводило к тому, что у меня использовался только один middleware, но как два разных.

Вывод: не полениться и настроить eslint - очень хорошая идея.

→ Ссылка