Feature/rework middlewares chain (#664)

* Reworked middlewares chain

* Added description for router name

* Added patch-notes

* Fixed type hints
This commit is contained in:
Alex Root Junior 2021-08-17 00:43:27 +03:00 committed by GitHub
parent c1f605c6f5
commit 9238533e93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 29 deletions

View file

@ -98,7 +98,8 @@ class Dispatcher(Router):
token = Bot.set_current(bot)
try:
response = await self.update.trigger(update, bot=bot, **kwargs)
kwargs.update(bot=bot)
response = await self.update.wrap_outer_middleware(self.update.trigger, update, kwargs)
handled = response is not UNHANDLED
return response
finally:

View file

@ -84,13 +84,13 @@ class TelegramEventObserver:
:param *:
"""
middlewares = []
for router in reversed(list(self.router.chain_head)):
observer = router.observers[self.event_name]
if outer:
middlewares.extend(observer.outer_middlewares)
else:
if outer:
middlewares.extend(self.outer_middlewares)
else:
for router in reversed(list(self.router.chain_head)):
observer = router.observers[self.event_name]
middlewares.extend(observer.middlewares)
return middlewares
def resolve_filters(self, full_config: Dict[str, Any]) -> List[BaseFilter]:
@ -148,15 +148,17 @@ class TelegramEventObserver:
middleware = functools.partial(m, middleware)
return middleware
def wrap_outer_middleware(
self, callback: Any, event: TelegramObject, data: Dict[str, Any]
) -> Any:
wrapped_outer = self._wrap_middleware(self._resolve_middlewares(outer=True), callback)
return wrapped_outer(event, data)
async def trigger(self, event: TelegramObject, **kwargs: Any) -> Any:
"""
Propagate event to handlers and stops propagation on first match.
Handler will be called when all its filters is pass.
"""
wrapped_outer = self._wrap_middleware(self._resolve_middlewares(outer=True), self._trigger)
return await wrapped_outer(event, kwargs)
async def _trigger(self, event: TelegramObject, **kwargs: Any) -> Any:
# Check globally defined filters before any other handler will be checked
result, data = await self._handler.check(event, **kwargs)
if not result:

View file

@ -21,16 +21,17 @@ class Router:
- By observer method - :obj:`router.<event_type>.register(handler, <filters, ...>)`
- By decorator - :obj:`@router.<event_type>(<filters, ...>)`
"""
def __init__(self, use_builtin_filters: bool = True) -> None:
def __init__(self, use_builtin_filters: bool = True, name: Optional[str] = None) -> None:
"""
:param use_builtin_filters: `aiogram` has many builtin filters and you can controll automatic registration of this filters in factory
:param name: Optional router name, can be useful for debugging
"""
self.use_builtin_filters = use_builtin_filters
self.name = name or hex(id(self))
self._parent_router: Optional[Router] = None
self.sub_routers: List[Router] = []
@ -84,9 +85,30 @@ class Router:
for builtin_filter in BUILTIN_FILTERS.get(name, ()):
observer.bind_filter(builtin_filter)
def __str__(self) -> str:
return f"{type(self).__name__} {self.name!r}"
def __repr__(self) -> str:
return f"<{self}>"
async def propagate_event(self, update_type: str, event: TelegramObject, **kwargs: Any) -> Any:
kwargs.update(event_router=self)
observer = self.observers[update_type]
async def _wrapped(telegram_event: TelegramObject, **data: Any) -> Any:
return await self._propagate_event(
observer=observer, update_type=update_type, event=telegram_event, **data
)
return await observer.wrap_outer_middleware(_wrapped, event=event, data=kwargs)
async def _propagate_event(
self,
observer: TelegramEventObserver,
update_type: str,
event: TelegramObject,
**kwargs: Any,
) -> Any:
response = await observer.trigger(event, **kwargs)
if response is REJECTED:
return UNHANDLED