import logging import threading from managers.telegram_manager import TelegramManager from pymongo import MongoClient from pymongo.errors import ConnectionFailure class TelegramManagerFactory: """Factory para gestionar múltiples instancias de TelegramManager (una por usuario)""" _instances = {} # Dict: username -> TelegramManager _lock = threading.Lock() _mongodb_client = None _mongodb_config = None @classmethod def initialize(cls, mongodb_config=None): """Inicializa la factory con configuración de MongoDB""" cls._mongodb_config = mongodb_config cls.logger = logging.getLogger(__name__) @classmethod def _get_mongodb_client(cls): """Obtiene cliente de MongoDB para leer configuración de Telegram""" if cls._mongodb_client is not None: return cls._mongodb_client if not cls._mongodb_config: return None try: mongodb_config = cls._mongodb_config.get('mongodb', {}) mongodb_host = mongodb_config.get('host', 'localhost') mongodb_port = mongodb_config.get('port', 27017) mongodb_database = mongodb_config.get('database', 'wallabicher') mongodb_username = mongodb_config.get('username') mongodb_password = mongodb_config.get('password') mongodb_auth_source = mongodb_config.get('auth_source', 'admin') if mongodb_username and mongodb_password: connection_string = f"mongodb://{mongodb_username}:{mongodb_password}@{mongodb_host}:{mongodb_port}/?authSource={mongodb_auth_source}" else: connection_string = f"mongodb://{mongodb_host}:{mongodb_port}/" client = MongoClient(connection_string, serverSelectionTimeoutMS=5000) client.admin.command('ping') cls._mongodb_client = client[mongodb_database] return cls._mongodb_client except Exception as e: cls.logger.error(f"Error conectando a MongoDB para configuración de Telegram: {e}") return None @classmethod def get_telegram_config(cls, username): """Obtiene configuración de Telegram para un usuario desde MongoDB""" db = cls._get_mongodb_client() if db is None: return None try: users_collection = db['users'] user = users_collection.find_one({'username': username}) if user and 'telegram' in user: telegram_config = user['telegram'] return { 'token': telegram_config.get('token'), 'channel': telegram_config.get('channel'), 'enable_polling': telegram_config.get('enable_polling', False) } except Exception as e: cls.logger.error(f"Error obteniendo configuración de Telegram para {username}: {e}") return None @classmethod def get_manager(cls, username): """ Obtiene o crea un TelegramManager para un usuario específico Args: username: Nombre de usuario Returns: TelegramManager o None si no hay configuración """ if username is None: # Si no hay username, usar configuración global (compatibilidad) with cls._lock: if 'global' not in cls._instances: try: cls._instances['global'] = TelegramManager() except Exception as e: cls.logger.error(f"Error creando TelegramManager global: {e}") return None return cls._instances.get('global') with cls._lock: # Si ya existe, retornarlo if username in cls._instances: return cls._instances[username] # Obtener configuración de MongoDB config = cls.get_telegram_config(username) if not config or not config.get('token') or not config.get('channel'): cls.logger.warning(f"No hay configuración de Telegram para usuario '{username}'") return None # Crear nueva instancia try: manager = TelegramManager( token=config['token'], channel=config['channel'], enable_polling=config.get('enable_polling', False), username=username ) cls._instances[username] = manager cls.logger.info(f"TelegramManager creado para usuario '{username}'") return manager except Exception as e: cls.logger.error(f"Error creando TelegramManager para usuario '{username}': {e}") return None @classmethod def remove_manager(cls, username): """Elimina un TelegramManager del cache""" with cls._lock: if username in cls._instances: del cls._instances[username] cls.logger.info(f"TelegramManager eliminado del cache para usuario '{username}'") @classmethod def clear_cache(cls): """Limpia todo el cache de managers""" with cls._lock: cls._instances.clear() cls.logger.info("Cache de TelegramManager limpiado")