Files
telegram-helper-bot/.cursor/rules/handlers-patterns.md
Andrey d2d7c83575 Обновлен Python до версии 3.11.9 и изменены зависимости в Dockerfile и pyproject.toml. Удалены устаревшие файлы RATE_LIMITING_SOLUTION.md и тесты для rate limiting.
Обновлены пути к библиотекам в Dockerfile для соответствия новой версии Python.
Исправлены все тесты, теперь все проходят
2026-01-25 16:07:27 +03:00

216 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: "Паттерны для создания handlers, services и обработки событий aiogram"
globs: ["helper_bot/handlers/**/*.py"]
---
# Паттерны для Handlers
## Структура модуля handler
Каждый модуль handler (admin, callback, group, private, voice) должен содержать:
```
handlers/{module}/
├── __init__.py # Экспорт router
├── {module}_handlers.py # Основные handlers
├── services.py # Бизнес-логика
├── exceptions.py # Кастомные исключения
├── dependencies.py # Dependency injection (опционально)
├── constants.py # Константы (FSM states, messages)
└── utils.py # Вспомогательные функции (опционально)
```
## Создание Router
```python
from aiogram import Router
# Создаем роутер
router = Router()
# Регистрируем middleware (если нужно)
router.message.middleware(SomeMiddleware())
# Экспортируем в __init__.py
# from .{module}_handlers import router
```
## Структура Handler
```python
from aiogram import Router, types
from aiogram.filters import Command, StateFilter
from aiogram.fsm.context import FSMContext
from helper_bot.filters.main import ChatTypeFilter
from logs.custom_logger import logger
from helper_bot.utils.metrics import track_time, track_errors
router = Router()
@router.message(
ChatTypeFilter(chat_type=["private"]),
Command('command_name')
)
@track_time("handler_name", "module_name")
@track_errors("module_name", "handler_name")
async def handler_function(
message: types.Message,
state: FSMContext,
bot_db: AsyncBotDB, # Из DependenciesMiddleware
settings: dict, # Из DependenciesMiddleware
**kwargs
):
"""Описание handler."""
try:
# Логирование
logger.info(f"Обработка команды от пользователя: {message.from_user.id}")
# Получение данных из state (если нужно)
data = await state.get_data()
# Вызов сервиса для бизнес-логики
service = SomeService(bot_db, settings)
result = await service.do_something()
# Ответ пользователю
await message.answer("Результат")
# Обновление state (если нужно)
await state.set_state("NEW_STATE")
except SomeCustomException as e:
# Обработка кастомных исключений
await message.answer(f"Ошибка: {str(e)}")
logger.error(f"Ошибка в handler: {e}")
except Exception as e:
# Обработка общих ошибок
await handle_error(message, e, state)
logger.error(f"Неожиданная ошибка: {e}")
```
## Service Layer
Бизнес-логика выносится в сервисы:
```python
from logs.custom_logger import logger
from helper_bot.utils.metrics import track_time, track_errors
class SomeService:
"""Сервис для работы с ..."""
def __init__(self, bot_db: AsyncBotDB, settings: dict):
self.bot_db = bot_db
self.settings = settings
@track_time("method_name", "service_name")
@track_errors("service_name", "method_name")
async def do_something(self) -> SomeResult:
"""Описание метода."""
try:
# Работа с БД через bot_db
data = await self.bot_db.some_method()
# Бизнес-логика
result = self._process_data(data)
return result
except Exception as e:
logger.error(f"Ошибка в сервисе: {e}")
raise
```
## Dependency Injection
### Через DependenciesMiddleware (глобально)
- `bot_db: AsyncBotDB` - доступен во всех handlers
- `settings: dict` - настройки из .env
- `bot: Bot` - экземпляр бота
- `dp: Dispatcher` - dispatcher
### Через MagicData (локально)
```python
from aiogram.filters import MagicData
from typing import Annotated
from helper_bot.handlers.admin.dependencies import BotDB, Settings
@router.message(
Command('admin'),
MagicData(bot_db=BotDB, settings=Settings)
)
async def handler(
message: types.Message,
bot_db: Annotated[AsyncBotDB, BotDB],
settings: Annotated[dict, Settings]
):
...
```
### Через фабрики (для сервисов)
```python
# В dependencies.py
def get_some_service() -> SomeService:
"""Фабрика для SomeService"""
bdf = get_global_instance()
db = bdf.get_db()
settings = bdf.settings
return SomeService(db, settings)
# В handlers
@router.message(Command('cmd'))
async def handler(
message: types.Message,
service: Annotated[SomeService, get_some_service()]
):
...
```
## FSM (Finite State Machine)
```python
# Определение состояний в constants.py
FSM_STATES = {
"ADMIN": "ADMIN",
"AWAIT_INPUT": "AWAIT_INPUT",
...
}
# Установка состояния
await state.set_state(FSM_STATES["ADMIN"])
# Получение состояния
current_state = await state.get_state()
# Сохранение данных
await state.update_data(key=value)
# Получение данных
data = await state.get_data()
value = data.get("key")
# Очистка состояния
await state.clear()
```
## Фильтры
Используйте кастомные фильтры из `helper_bot.filters.main`:
- `ChatTypeFilter` - фильтр по типу чата (private, group, supergroup)
## Декораторы для метрик
Всегда добавляйте декораторы метрик к handlers и методам сервисов:
```python
@track_time("handler_name", "module_name") # Измерение времени выполнения
@track_errors("module_name", "handler_name") # Отслеживание ошибок
@db_query_time("method_name", "table_name", "operation") # Для БД операций
```
## Обработка ошибок
- Используйте кастомные исключения из `exceptions.py`
- Обрабатывайте исключения в handlers
- Логируйте все ошибки через `logger.error()`
- Используйте декоратор `@error_handler` для автоматической обработки (если есть)