Добавлен Middleware

This commit is contained in:
2025-06-23 09:49:24 +03:00
parent 8aa9c65fcc
commit 512eb9a4af
9 changed files with 253 additions and 49 deletions

View File

@@ -1,4 +1,4 @@
from typing import Callable, List
from typing import Any, Callable, Dict, List
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
@@ -6,6 +6,8 @@ from magic_filter import MagicFilter
from uvicorn import Config, Server
from aiohttp import ClientConnectorError
from maxapi.filters.middleware import BaseMiddleware
from .filters.handler import Handler
from .context import MemoryContext
@@ -36,6 +38,8 @@ class Dispatcher:
self.contexts: List[MemoryContext] = []
self.routers: List[Router] = []
self.filters: List[MagicFilter] = []
self.middlewares: List[BaseMiddleware] = []
self.bot = None
self.on_started_func = None
@@ -78,7 +82,7 @@ class Dispatcher:
handlers_count = 0
for router in self.routers:
for handler in router.event_handlers:
for _ in router.event_handlers:
handlers_count += 1
logger_dp.info(f'{handlers_count} событий на обработку')
@@ -105,6 +109,30 @@ 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]
):
for middleware in middlewares:
result = await middleware.process_middleware(
event_object=event_object,
result_data_kwargs=result_data_kwargs
)
if result == None or result == False:
return
elif result == True:
result = {}
for key, value in result.items():
result_data_kwargs[key] = value
return result_data_kwargs
async def handle(self, event_object: UpdateUnion):
@@ -113,54 +141,68 @@ class Dispatcher:
Args:
event_object: Объект события для обработки
"""
ids = event_object.get_ids()
is_handled = False
for router in self.routers:
try:
ids = event_object.get_ids()
memory_context = self.__get_memory_context(*ids)
kwargs = {'context': memory_context}
if is_handled:
break
is_handled = False
if router.filters:
if not filter_attrs(event_object, *router.filters):
continue
for handler in router.event_handlers:
for router in self.routers:
if is_handled:
break
if router.filters:
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:
continue
if handler.filters:
if not filter_attrs(event_object, *handler.filters):
if not handler.update_type == event_object.update_type:
continue
memory_context = self.__get_memory_context(*ids)
if not handler.state == await memory_context.get_state() \
and handler.state:
continue
func_args = handler.func_event.__annotations__.keys()
if handler.filters:
if not filter_attrs(event_object, *handler.filters):
continue
kwargs = {'context': memory_context}
for key in kwargs.copy().keys():
if not key in func_args:
del kwargs[key]
if not handler.state == await memory_context.get_state() \
and handler.state:
continue
func_args = handler.func_event.__annotations__.keys()
kwargs = await self.process_middlewares(
middlewares=handler.middlewares,
event_object=event_object,
result_data_kwargs=kwargs
)
if not kwargs:
continue
if handler.middleware:
await handler.middleware()
for key in kwargs.copy().keys():
if not key in func_args:
del kwargs[key]
await handler.func_event(event_object, **kwargs)
await handler.func_event(event_object, **kwargs)
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
is_handled = True
break
is_handled = True
break
if not is_handled:
logger_dp.info(f'Проигнорировано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
if not is_handled:
logger_dp.info(f'Проигнорировано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
except Exception as e:
logger_dp.error(f"Ошибка при обработке события: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]} | {e} ")
async def start_polling(self, bot: Bot):
@@ -187,10 +229,7 @@ class Dispatcher:
)
for event in processed_events:
try:
await self.handle(event)
except Exception as e:
logger_dp.error(f"Ошибка при обработке события: {event.update_type}: {e}")
await self.handle(event)
except ClientConnectorError:
logger_dp.error(f'Ошибка подключения: {e}')
except Exception as e:

View File

@@ -1,4 +1,4 @@
from typing import Callable
from typing import Callable, List
from magic_filter import F, MagicFilter
@@ -45,7 +45,7 @@ class Handler:
self.update_type: UpdateType = update_type
self.filters = []
self.state: State = None
self.middleware: BaseMiddleware = None
self.middlewares: List[BaseMiddleware] = []
for arg in args:
if isinstance(arg, MagicFilter):
@@ -55,7 +55,7 @@ class Handler:
elif isinstance(arg, Command):
self.filters.insert(0, F.message.body.text.startswith(arg.command))
elif isinstance(arg, BaseMiddleware):
self.middleware = arg
self.middlewares.append(arg)
else:
logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при '
f'регистрации функции `{func_event.__name__}`')

View File

@@ -1,6 +1,23 @@
from typing import Any, Dict
from ..types.updates import UpdateUnion
class BaseMiddleware:
def __init__(self):
...
...
async def process_middleware(
self,
result_data_kwargs: Dict[str, Any],
event_object: UpdateUnion
):
kwargs_temp = {'data': result_data_kwargs.copy()}
for key in kwargs_temp.copy().keys():
if not key in self.__call__.__annotations__.keys():
del kwargs_temp[key]
result: Dict[str, Any] = await self(event_object, **kwargs_temp)
return result

View File

@@ -9,6 +9,7 @@ from ..types.updates.message_edited import MessageEdited
from ..types.updates.message_removed import MessageRemoved
from ..types.updates.user_added import UserAdded
from ..types.updates.user_removed import UserRemoved
from ..types.updates import UpdateUnion
from ..types.attachments.attachment import PhotoAttachmentPayload
from ..types.attachments.attachment import OtherAttachmentPayload
@@ -20,12 +21,14 @@ from ..types.attachments.buttons.chat_button import ChatButton
from ..types.attachments.buttons.link_button import LinkButton
from ..types.attachments.buttons.request_contact import RequestContact
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
from ..types.message import Message
from ..types.command import Command, BotCommand
from .input_media import InputMedia
__all__ = [
UpdateUnion,
InputMedia,
BotCommand,
CallbackButton,

View File

@@ -1,5 +1,7 @@
from typing import Optional
from maxapi.enums.button_type import ButtonType
from .button import Button
@@ -7,7 +9,6 @@ class ChatButton(Button):
"""
Attributes:
type: Тип кнопки (наследуется от Button)
text: Текст кнопки (наследуется от Button)
chat_title: Название чата (до 128 символов)
chat_description: Описание чата (до 256 символов)
@@ -15,6 +16,7 @@ class ChatButton(Button):
uuid: Уникальный идентификатор чата
"""
type: ButtonType = ButtonType.CHAT
chat_title: Optional[str] = None
chat_description: Optional[str] = None
start_payload: Optional[str] = None