Files
AnonBot/dependencies.py

388 lines
15 KiB
Python
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.
"""
Система инъекции зависимостей для AnonBot с использованием MagicData
"""
from typing import Any, Dict, Optional
from aiogram import BaseMiddleware
from aiogram.fsm.context import FSMContext
from aiogram.fsm.storage.base import BaseStorage
from aiogram.types import TelegramObject
from config import config
from services.auth.auth_new import AuthService
from services.infrastructure.database import DatabaseService
from services.infrastructure.logger import get_logger
from services.business.message_service import MessageService
from services.business.pagination_service import PaginationService
from services.permissions import get_permission_checker, init_permission_checker
from services.permissions.init_permissions import init_all_permissions
from services.business.question_service import QuestionService
from services.rate_limiting.rate_limit_service import RateLimitService
from services.business.user_service import UserService
from services.utils import UtilsService
from services.validation import InputValidator
logger = get_logger(__name__)
class Dependencies:
"""Контейнер зависимостей для инъекции в обработчики"""
def __init__(self):
self._database: Optional[DatabaseService] = None
self._auth: Optional[AuthService] = None
self._utils: Optional[UtilsService] = None
self._user_service: Optional[UserService] = None
self._question_service: Optional[QuestionService] = None
self._message_service: Optional[MessageService] = None
self._pagination_service: Optional[PaginationService] = None
self._rate_limit_service: Optional[RateLimitService] = None
self._validator: Optional[InputValidator] = None
self._config = config
@property
def database(self) -> DatabaseService:
"""Получение экземпляра DatabaseService"""
if self._database is None:
self._database = DatabaseService(config.DATABASE_PATH)
return self._database
@property
def auth(self) -> AuthService:
"""Получение экземпляра AuthService (с системой разрешений)"""
if self._auth is None:
self._auth = AuthService(self.database, config)
return self._auth
@property
def utils(self) -> UtilsService:
"""Получение экземпляра UtilsService"""
if self._utils is None:
self._utils = UtilsService(self.database)
return self._utils
@property
def user_service(self) -> UserService:
"""Получение экземпляра UserService"""
if self._user_service is None:
self._user_service = UserService(self.database, self.utils)
return self._user_service
@property
def question_service(self) -> QuestionService:
"""Получение экземпляра QuestionService"""
if self._question_service is None:
self._question_service = QuestionService(self.database, self.utils)
return self._question_service
@property
def message_service(self) -> MessageService:
"""Получение экземпляра MessageService"""
if self._message_service is None:
# Убеждаемся, что rate_limit_service создан первым
rate_limit_service = self.rate_limit_service
self._message_service = MessageService(rate_limit_service)
return self._message_service
@property
def pagination_service(self) -> PaginationService:
"""Получение экземпляра PaginationService"""
if self._pagination_service is None:
self._pagination_service = PaginationService()
return self._pagination_service
@property
def rate_limit_service(self) -> RateLimitService:
"""Получение экземпляра RateLimitService"""
if self._rate_limit_service is None:
self._rate_limit_service = RateLimitService()
return self._rate_limit_service
@property
def validator(self) -> InputValidator:
"""Получение экземпляра InputValidator"""
if self._validator is None:
self._validator = InputValidator()
return self._validator
@property
def config(self):
"""Получение конфигурации"""
return self._config
async def init(self):
"""Инициализация всех сервисов"""
try:
await self.database.init()
# Инициализируем систему разрешений
init_all_permissions()
init_permission_checker(self.database, self.config)
logger.info("Все зависимости инициализированы")
except Exception as e:
logger.error(f"❌ Ошибка инициализации зависимостей: {e}")
raise
async def close(self):
"""Закрытие всех соединений"""
try:
if self._database:
await self._database.close()
logger.info("Все зависимости закрыты")
except Exception as e:
logger.error(f"❌ Ошибка закрытия зависимостей: {e}")
class DependencyMiddleware(BaseMiddleware):
"""Middleware для инъекции зависимостей в обработчики"""
def __init__(self, dependencies: Dependencies):
super().__init__()
self.dependencies = dependencies
async def __call__(
self,
handler,
event: TelegramObject,
data: Dict[str, Any]
) -> Any:
"""Инъекция зависимостей в контекст обработчика"""
# Добавляем зависимости в контекст
data['deps'] = self.dependencies
data['database'] = self.dependencies.database
data['auth'] = self.dependencies.auth
data['utils'] = self.dependencies.utils
data['user_service'] = self.dependencies.user_service
data['question_service'] = self.dependencies.question_service
data['message_service'] = self.dependencies.message_service
data['pagination_service'] = self.dependencies.pagination_service
data['rate_limit_service'] = self.dependencies.rate_limit_service
data['validator'] = self.dependencies.validator
data['config'] = self.dependencies.config
data['permission_checker'] = get_permission_checker()
return await handler(event, data)
# Глобальный экземпляр зависимостей
dependencies = Dependencies()
def get_dependencies() -> Dependencies:
"""Получение глобального экземпляра зависимостей"""
return dependencies
def get_database() -> DatabaseService:
"""Получение экземпляра DatabaseService (для обратной совместимости)"""
return dependencies.database
def get_auth() -> AuthService:
"""Получение экземпляра AuthService (с системой разрешений)"""
return dependencies.auth
def get_utils() -> UtilsService:
"""Получение экземпляра UtilsService"""
return dependencies.utils
# Декораторы для удобства использования
def inject_database(func):
"""Декоратор для инъекции DatabaseService"""
async def wrapper(*args, **kwargs):
if 'database' not in kwargs:
kwargs['database'] = get_database()
return await func(*args, **kwargs)
return wrapper
def inject_auth(func):
"""Декоратор для инъекции AuthService"""
async def wrapper(*args, **kwargs):
if 'auth' not in kwargs:
kwargs['auth'] = get_auth()
return await func(*args, **kwargs)
return wrapper
def inject_utils(func):
"""Декоратор для инъекции UtilsService"""
async def wrapper(*args, **kwargs):
if 'utils' not in kwargs:
kwargs['utils'] = get_utils()
return await func(*args, **kwargs)
return wrapper
def get_user_service() -> UserService:
"""Получение экземпляра UserService"""
return dependencies.user_service
def get_question_service() -> QuestionService:
"""Получение экземпляра QuestionService"""
return dependencies.question_service
def get_message_service() -> MessageService:
"""Получение экземпляра MessageService"""
return dependencies.message_service
def get_pagination_service() -> PaginationService:
"""Получение экземпляра PaginationService"""
return dependencies.pagination_service
def get_rate_limit_service() -> RateLimitService:
"""Получение экземпляра RateLimitService"""
return dependencies.rate_limit_service
def get_validator() -> InputValidator:
"""Получение экземпляра InputValidator"""
return dependencies.validator
def inject_all(func):
"""Декоратор для инъекции всех основных сервисов"""
async def wrapper(*args, **kwargs):
# Фильтруем kwargs, убираем лишние параметры
import inspect
sig = inspect.signature(func)
filtered_kwargs = {k: v for k, v in kwargs.items() if k in sig.parameters}
# Добавляем только те сервисы, которые ожидает функция
if 'database' in sig.parameters and 'database' not in filtered_kwargs:
filtered_kwargs['database'] = get_database()
if 'auth' in sig.parameters and 'auth' not in filtered_kwargs:
filtered_kwargs['auth'] = get_auth()
if 'utils' in sig.parameters and 'utils' not in filtered_kwargs:
filtered_kwargs['utils'] = get_utils()
if 'user_service' in sig.parameters and 'user_service' not in filtered_kwargs:
filtered_kwargs['user_service'] = get_user_service()
if 'question_service' in sig.parameters and 'question_service' not in filtered_kwargs:
filtered_kwargs['question_service'] = get_question_service()
if 'message_service' in sig.parameters and 'message_service' not in filtered_kwargs:
filtered_kwargs['message_service'] = get_message_service()
if 'pagination_service' in sig.parameters and 'pagination_service' not in filtered_kwargs:
filtered_kwargs['pagination_service'] = get_pagination_service()
if 'rate_limit_service' in sig.parameters and 'rate_limit_service' not in filtered_kwargs:
filtered_kwargs['rate_limit_service'] = get_rate_limit_service()
if 'validator' in sig.parameters and 'validator' not in filtered_kwargs:
filtered_kwargs['validator'] = get_validator()
if 'config' in sig.parameters and 'config' not in filtered_kwargs:
filtered_kwargs['config'] = get_dependencies().config
return await func(*args, **filtered_kwargs)
return wrapper
def get_database_service() -> DatabaseService:
"""Получить экземпляр DatabaseService"""
return get_dependencies().database
# Специализированные декораторы для конкретных случаев использования
def inject_question_services(func):
"""Декоратор для инъекции сервисов, нужных для обработки вопросов"""
async def wrapper(*args, **kwargs):
if 'question_service' not in kwargs:
kwargs['question_service'] = get_question_service()
if 'user_service' not in kwargs:
kwargs['user_service'] = get_user_service()
if 'message_service' not in kwargs:
kwargs['message_service'] = get_message_service()
if 'validator' not in kwargs:
kwargs['validator'] = get_validator()
return await func(*args, **kwargs)
return wrapper
def inject_answer_services(func):
"""Декоратор для инъекции сервисов, нужных для обработки ответов"""
async def wrapper(*args, **kwargs):
if 'validator' not in kwargs:
kwargs['validator'] = get_validator()
return await func(*args, **kwargs)
return wrapper
def inject_validator(func):
"""Декоратор для инъекции только валидатора"""
async def wrapper(*args, **kwargs):
if 'validator' not in kwargs:
kwargs['validator'] = get_validator()
return await func(*args, **kwargs)
return wrapper
def inject_message_services(func):
"""Декоратор для инъекции сервисов, нужных для отправки сообщений"""
async def wrapper(*args, **kwargs):
if 'message_service' not in kwargs:
kwargs['message_service'] = get_message_service()
if 'user_service' not in kwargs:
kwargs['user_service'] = get_user_service()
return await func(*args, **kwargs)
return wrapper
def inject_start_services(func):
"""Декоратор для инъекции сервисов, нужных для команды /start"""
async def wrapper(*args, **kwargs):
if 'user_service' not in kwargs:
kwargs['user_service'] = get_user_service()
if 'auth' not in kwargs:
kwargs['auth'] = get_auth()
if 'utils' not in kwargs:
kwargs['utils'] = get_utils()
if 'message_service' not in kwargs:
kwargs['message_service'] = get_message_service()
if 'validator' not in kwargs:
kwargs['validator'] = get_validator()
return await func(*args, **kwargs)
return wrapper
def inject_link_services(func):
"""Декоратор для инъекции сервисов, нужных для кнопки 'Моя ссылка'"""
async def wrapper(*args, **kwargs):
if 'user_service' not in kwargs:
kwargs['user_service'] = get_user_service()
if 'message_service' not in kwargs:
kwargs['message_service'] = get_message_service()
return await func(*args, **kwargs)
return wrapper
def inject_main_menu_services(func):
"""Декоратор для инъекции сервисов, нужных для кнопки 'Главное меню'"""
async def wrapper(*args, **kwargs):
if 'auth' not in kwargs:
kwargs['auth'] = get_auth()
if 'message_service' not in kwargs:
kwargs['message_service'] = get_message_service()
return await func(*args, **kwargs)
return wrapper
def inject_admin_services(func):
"""Декоратор для инъекции сервисов, нужных для админ-панели"""
async def wrapper(*args, **kwargs):
if 'rate_limit_service' not in kwargs:
kwargs['rate_limit_service'] = get_rate_limit_service()
if 'message_service' not in kwargs:
kwargs['message_service'] = get_message_service()
if 'auth' not in kwargs:
kwargs['auth'] = get_auth()
return await func(*args, **kwargs)
return wrapper