Мидлвари

Мидлвари позволяют перехватывать и изменять события до или после их обработки обработчиками. Это инструмент для логирования, обработки ошибок, внедрения зависимостей (DI) и управления контекстом.

В maxo есть два типа мидлварей, которые работают на разных этапах обработки события:

  1. Outer Middleware (внешние): выполняются до того, как сработают фильтры обработчика. Они оборачивают процесс поиска обработчика. Используйте их, если нужно выполнить действие для всех обновлений данного типа (например, логирование, установка глобального контекста, обработка ошибок).

  2. Inner Middleware (внутренние): выполняются после того, как фильтры конкретного обработчика прошли успешно, но перед (и после) самим обработчиком. Используйте их, если действие зависит от того, будет ли вызван обработчик (например, транзакции базы данных, специфичные проверки прав).

        graph TD
    Update["Входящее обновление"] --> OuterStart["Outer Middleware (начало)"]
    OuterStart --> Router["Поиск обработчика"]
    Router --> Filters{"Фильтры"}
    Filters -- Успех --> InnerStart["Inner Middleware (начало)"]
    InnerStart --> Handler["Вызов обработчика"]
    Handler --> InnerEnd["Inner Middleware (конец)"]
    InnerEnd --> OuterEnd["Outer Middleware (конец)"]
    Filters -- Неудачно --> NextHandler["Следующий обработчик/Роутер"]
    

Регистрация

Мидлвари регистрируются на уровне роутера или диспетчера для конкретного типа событий через соответствующие методы .middleware.outer() и .middleware.inner().

# Глобальная внешняя мидлварь для всех сообщений
dispatcher.message_created.middleware.outer(LoggingMiddleware())

# Внутренняя мидлварь для callback-кнопок в конкретном роутере
shop_router.message_callback.middleware.inner(TransactionMiddleware())

Написание своей мидлвари

Мидлварь - это класс, наследующий BaseMiddleware и реализующий асинхронный метод __call__.

from typing import Any

from maxo.routing.ctx import Ctx
from maxo.routing.interfaces.middleware import BaseMiddleware, NextMiddleware
from maxo.routing.updates import MessageCreated

class MyMiddleware(BaseMiddleware[MessageCreated]):
    async def __call__(
        self,
        update: MessageCreated,
        ctx: Ctx,
        next: NextMiddleware[MessageCreated],
    ) -> Any:
        # Код, выполняемый ДО обработчика
        print("Before handler")

        # Передача управления следующей мидлвари или обработчику
        result = await next(ctx)

        # Код, выполняемый ПОСЛЕ обработчика
        print("After handler")

        return result