""" Method rotation mixin for platform controllers. Provides method rotation functionality without breaking existing inheritance hierarchy. """ import logging from datetime import datetime from typing import Dict, Any, Optional from application.use_cases.method_rotation_use_case import MethodRotationUseCase, RotationContext from infrastructure.repositories.method_strategy_repository import MethodStrategyRepository from infrastructure.repositories.rotation_session_repository import RotationSessionRepository from infrastructure.repositories.platform_method_state_repository import PlatformMethodStateRepository from domain.entities.method_rotation import MethodStrategy, RotationSession, RiskLevel class MethodRotationMixin: """ Mixin class that adds method rotation capabilities to platform controllers. Can be mixed into existing controller classes without breaking inheritance. """ def _init_method_rotation_system(self): """Initialize the method rotation system components""" try: # Check if db_manager is available if not hasattr(self, 'db_manager') or self.db_manager is None: self.method_rotation_use_case = None return # Initialize repositories self.method_strategy_repo = MethodStrategyRepository(self.db_manager) self.rotation_session_repo = RotationSessionRepository(self.db_manager) self.platform_state_repo = PlatformMethodStateRepository(self.db_manager) # Initialize use case self.method_rotation_use_case = MethodRotationUseCase( strategy_repo=self.method_strategy_repo, session_repo=self.rotation_session_repo, state_repo=self.platform_state_repo ) # Initialize rotation state self.current_rotation_session = None self.current_rotation_context = None self.logger.info(f"Method rotation system initialized for {self.platform_name}") except Exception as e: self.logger.error(f"Failed to initialize method rotation system: {e}") # Set to None so we can detect failures and fallback self.method_rotation_use_case = None def _apply_method_strategy(self, params: Dict[str, Any], strategy: MethodStrategy) -> Dict[str, Any]: """ Apply method strategy configuration to account creation parameters. Args: params: Original account creation parameters strategy: Selected method strategy Returns: Updated parameters with method-specific configuration """ updated_params = params.copy() # Apply method selection updated_params['registration_method'] = strategy.method_name # Apply method-specific configuration config = strategy.configuration if strategy.method_name.startswith('stealth_'): # Instagram anti-bot strategy methods updated_params['stealth_method'] = strategy.method_name updated_params['enhanced_stealth'] = config.get('enhanced_stealth', False) updated_params['user_agent_rotation'] = config.get('user_agent_rotation', False) updated_params['fingerprint_complexity'] = config.get('fingerprint_complexity', 'basic') updated_params['canvas_noise'] = config.get('canvas_noise', False) updated_params['webrtc_protection'] = config.get('webrtc_protection', 'basic') updated_params['viewport_randomization'] = config.get('viewport_randomization', False) updated_params['navigator_spoof'] = config.get('navigator_spoof', False) updated_params['timing_randomization'] = config.get('timing_randomization', False) updated_params['screen_resolution_spoof'] = config.get('screen_resolution_spoof', False) updated_params['memory_spoof'] = config.get('memory_spoof', False) updated_params['hardware_spoof'] = config.get('hardware_spoof', False) elif strategy.method_name == 'email': # Email method configuration (legacy) updated_params['email_domain'] = config.get('email_domain', self.DEFAULT_EMAIL_DOMAIN) updated_params['require_phone_verification'] = config.get('require_phone_verification', False) updated_params['auto_verify_email'] = config.get('auto_verify_email', True) elif strategy.method_name == 'phone': # Phone method configuration (legacy) updated_params['registration_method'] = 'phone' updated_params['require_email_backup'] = config.get('require_email_backup', True) updated_params['phone_verification_timeout'] = config.get('phone_verification_timeout', 300) elif strategy.method_name == 'social_login': # Social login configuration (legacy) updated_params['registration_method'] = 'social' updated_params['social_providers'] = config.get('supported_providers', ['facebook']) updated_params['fallback_to_email'] = config.get('fallback_to_email', True) elif strategy.method_name in ['standard_registration', 'recovery_registration']: # Gmail-specific methods updated_params['registration_method'] = strategy.method_name updated_params['recovery_email'] = config.get('recovery_email', False) updated_params['recovery_phone'] = config.get('recovery_phone', False) # Add strategy metadata updated_params['_method_strategy'] = { 'strategy_id': strategy.strategy_id, 'method_name': strategy.method_name, 'priority': strategy.priority, 'risk_level': strategy.risk_level.value, 'effectiveness_score': strategy.effectiveness_score } return updated_params def handle_method_failure(self, error_details: Dict[str, Any]) -> bool: """ Handle method failure and attempt rotation to next best method. Args: error_details: Details about the failure Returns: True if rotation succeeded and retry should be attempted, False otherwise """ if not self.method_rotation_use_case or not self.current_rotation_session: return False try: # Record the failure self.method_rotation_use_case.record_method_result( session_id=self.current_rotation_session.session_id, method_name=self.current_rotation_session.current_method, success=False, error_details=error_details ) # Check if rotation should occur if self.method_rotation_use_case.should_rotate_method(self.current_rotation_session.session_id): # Attempt rotation next_method = self.method_rotation_use_case.rotate_method( session_id=self.current_rotation_session.session_id, reason=f"Method failure: {error_details.get('error_type', 'unknown')}" ) if next_method: self.logger.info(f"Rotating from {self.current_rotation_session.current_method} to {next_method.method_name}") # Update current session reference self.current_rotation_session = self.rotation_session_repo.find_by_id( self.current_rotation_session.session_id ) return True else: self.logger.warning("No alternative methods available for rotation") else: self.logger.info("Rotation not triggered - continuing with current method") except Exception as e: self.logger.error(f"Method rotation failed: {e}") return False def handle_method_success(self, result: Dict[str, Any]) -> None: """ Handle successful method execution. Args: result: Result details from successful execution """ if not self.method_rotation_use_case or not self.current_rotation_session: return try: execution_time = result.get('execution_time', 0.0) # Record the success self.method_rotation_use_case.record_method_result( session_id=self.current_rotation_session.session_id, method_name=self.current_rotation_session.current_method, success=True, execution_time=execution_time ) self.logger.info(f"Method {self.current_rotation_session.current_method} succeeded in {execution_time:.2f}s") except Exception as e: self.logger.error(f"Failed to record method success: {e}") def get_rotation_status(self) -> Optional[Dict[str, Any]]: """ Get current rotation session status. Returns: Dictionary with rotation status information or None if no active session """ if not self.method_rotation_use_case or not self.current_rotation_session: return None try: return self.method_rotation_use_case.get_session_status( self.current_rotation_session.session_id ) except Exception as e: self.logger.error(f"Failed to get rotation status: {e}") return None def get_platform_method_recommendations(self) -> Dict[str, Any]: """ Get method recommendations and insights for the current platform. Returns: Dictionary with recommendations and platform insights """ if not self.method_rotation_use_case: return {} try: return self.method_rotation_use_case.get_platform_method_recommendations( self.platform_name.lower() ) except Exception as e: self.logger.error(f"Failed to get method recommendations: {e}") return {} def enable_emergency_mode(self, reason: str = "manual_override") -> None: """ Enable emergency mode for the platform. Args: reason: Reason for enabling emergency mode """ if not self.method_rotation_use_case: return try: self.method_rotation_use_case.enable_emergency_mode( self.platform_name.lower(), reason ) self.logger.warning(f"Emergency mode enabled for {self.platform_name}: {reason}") except Exception as e: self.logger.error(f"Failed to enable emergency mode: {e}") def disable_emergency_mode(self) -> None: """Disable emergency mode for the platform.""" if not self.method_rotation_use_case: return try: self.method_rotation_use_case.disable_emergency_mode( self.platform_name.lower() ) self.logger.info(f"Emergency mode disabled for {self.platform_name}") except Exception as e: self.logger.error(f"Failed to disable emergency mode: {e}") def _create_rotation_context(self, params: Dict[str, Any]) -> RotationContext: """ Create rotation context from account creation parameters. Args: params: Account creation parameters Returns: RotationContext for method selection """ return RotationContext( platform=self.platform_name.lower(), account_id=params.get('account_id'), fingerprint_id=params.get('fingerprint', {}).get('fingerprint_id'), excluded_methods=params.get('_excluded_methods', []), max_risk_level=RiskLevel(params.get('_max_risk_level', 'HIGH')), emergency_mode=params.get('_emergency_mode', False), session_metadata={ 'user_inputs': {k: v for k, v in params.items() if not k.startswith('_')}, 'creation_started_at': datetime.now().isoformat(), 'controller_type': self.__class__.__name__ } ) def _should_use_rotation_system(self) -> bool: """ Check if rotation system should be used. Returns: True if rotation system is available and should be used """ return ( self.method_rotation_use_case is not None and hasattr(self, 'db_manager') and self.db_manager is not None ) def cleanup_rotation_session(self) -> None: """Clean up current rotation session.""" if self.current_rotation_session: try: if self.current_rotation_session.is_active: self.rotation_session_repo.archive_session( self.current_rotation_session.session_id, False ) except Exception as e: self.logger.error(f"Failed to cleanup rotation session: {e}") finally: self.current_rotation_session = None self.current_rotation_context = None