From c8dd896691fdda328ee45c62cea6b31da403d2d3 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 27 Jul 2025 16:58:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=BD=D0=B0=20=D1=81=D0=B8=D1=81=D1=82=D0=B5?= =?UTF-8?q?=D0=BC=D0=B0=20Middleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maxapi/dispatcher.py | 77 +++++++++++++++--------------------- maxapi/filters/middleware.py | 33 ++++------------ 2 files changed, 39 insertions(+), 71 deletions(-) diff --git a/maxapi/dispatcher.py b/maxapi/dispatcher.py index eb6f80f..5d5cd29 100644 --- a/maxapi/dispatcher.py +++ b/maxapi/dispatcher.py @@ -2,7 +2,8 @@ from __future__ import annotations import asyncio -from typing import Any, Callable, Dict, List, TYPE_CHECKING, Optional +import functools +from typing import Any, Awaitable, Callable, Dict, List, TYPE_CHECKING, Optional from asyncio.exceptions import TimeoutError as AsyncioTimeoutError from aiohttp import ClientConnectorError @@ -120,6 +121,17 @@ class Dispatcher: self.bot._me = me logger_dp.info(f'Бот: @{me.username} first_name={me.first_name} id={me.user_id}') + + def build_middleware_chain( + self, + middlewares: list[BaseMiddleware], + handler: Callable[[Any, dict[str, Any]], Awaitable[Any]] + ) -> Callable[[Any, dict[str, Any]], Awaitable[Any]]: + + for mw in reversed(middlewares): + handler = functools.partial(mw, handler) + + return handler def include_routers(self, *routers: 'Router'): @@ -169,38 +181,18 @@ class Dispatcher: new_ctx = MemoryContext(chat_id, user_id) self.contexts.append(new_ctx) return new_ctx - - async def process_middlewares( - self, - middlewares: List[BaseMiddleware], - event_object: UpdateUnion, - result_data_kwargs: Dict[str, Any] - ): + + async def call_handler(self, handler, event_object, data): """ - Последовательно обрабатывает middleware цепочку. - - :param middlewares: Список middleware. - :param event_object: Объект события. - :param result_data_kwargs: Аргументы, передаваемые обработчику. - :return: Изменённые аргументы или None. + Правка аргументов конечной функции хендлера и ее вызов """ - for middleware in middlewares: - result = await middleware.process_middleware( - event_object=event_object, - result_data_kwargs=result_data_kwargs - ) - - if result is None or result is False: - return - - elif result is True: - continue - - result_data_kwargs.update(result) + func_args = handler.func_event.__annotations__.keys() + kwargs_filtered = {k: v for k, v in data.items() if k in func_args} + + await handler.func_event(event_object, **kwargs_filtered) - return result_data_kwargs async def handle(self, event_object: UpdateUnion): @@ -232,12 +224,6 @@ class Dispatcher: if not filter_attrs(event_object, *router.filters): continue - kwargs = await self.process_middlewares( - middlewares=router.middlewares, - event_object=event_object, - result_data_kwargs=kwargs - ) - for handler in router.event_handlers: if not handler.update_type == event_object.update_type: @@ -252,20 +238,19 @@ class Dispatcher: func_args = handler.func_event.__annotations__.keys() - kwargs = await self.process_middlewares( - middlewares=handler.middlewares, - event_object=event_object, - result_data_kwargs=kwargs - ) + if isinstance(router, Router): + full_middlewares = self.middlewares + router.middlewares + handler.middlewares + elif isinstance(router, Dispatcher): + full_middlewares = self.middlewares + handler.middlewares - if not kwargs: - continue + handler_chain = self.build_middleware_chain( + full_middlewares, + functools.partial(self.call_handler, handler) + ) + + kwargs_filtered = {k: v for k, v in kwargs.items() if k in func_args} - for key in kwargs.copy().keys(): - if key not in func_args: - del kwargs[key] - - await handler.func_event(event_object, **kwargs) + await handler_chain(event_object, kwargs_filtered) logger_dp.info(f'Обработано: {router_id} | {process_info}') diff --git a/maxapi/filters/middleware.py b/maxapi/filters/middleware.py index 0b86431..7382188 100644 --- a/maxapi/filters/middleware.py +++ b/maxapi/filters/middleware.py @@ -1,27 +1,10 @@ -from typing import Any, Dict -from ..types.updates import UpdateUnion - +from typing import Any, Callable, Awaitable class BaseMiddleware: - def __init__(self): - ... - - async def process_middleware( - self, - result_data_kwargs: Dict[str, Any], - event_object: UpdateUnion - ): - - # пока что заглушка - if result_data_kwargs is None: - return {} - - kwargs_temp = {'data': result_data_kwargs.copy()} - - for key in kwargs_temp.copy().keys(): - if key not in self.__call__.__annotations__.keys(): # type: ignore - del kwargs_temp[key] - - result: Dict[str, Any] = await self(event_object, **kwargs_temp) # type: ignore - - return result \ No newline at end of file + async def __call__( + self, + handler: Callable[[Any, dict[str, Any]], Awaitable[Any]], + event_object: Any, + data: dict[str, Any] + ) -> Any: + return await handler(event_object, data) \ No newline at end of file