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