""" Система инъекции зависимостей для 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