""" Operation Result Value Object - Standardisierte Ergebnisstruktur Backward-compatible Wrapper für konsistente Fehlerbehandlung """ from dataclasses import dataclass from typing import Optional, Any, Dict, Union from datetime import datetime import traceback @dataclass class OperationResult: """ Standardisierte Ergebnisstruktur für alle Operationen. Kompatibel mit bestehenden boolean und dict returns. """ success: bool data: Optional[Any] = None error_message: Optional[str] = None error_code: Optional[str] = None metadata: Optional[Dict[str, Any]] = None timestamp: Optional[datetime] = None legacy_result: Optional[Any] = None # Für backward compatibility def __post_init__(self): if self.timestamp is None: self.timestamp = datetime.now() @classmethod def success_result(cls, data: Any = None, metadata: Dict[str, Any] = None, legacy_result: Any = None): """Erstellt ein Erfolgsergebnis""" return cls( success=True, data=data, metadata=metadata or {}, legacy_result=legacy_result if legacy_result is not None else data ) @classmethod def error_result(cls, message: str, code: str = None, metadata: Dict[str, Any] = None, legacy_result: Any = None): """Erstellt ein Fehlerergebnis""" return cls( success=False, error_message=message, error_code=code, metadata=metadata or {}, legacy_result=legacy_result if legacy_result is not None else False ) @classmethod def from_exception(cls, exception: Exception, code: str = None, metadata: Dict[str, Any] = None): """Erstellt Fehlerergebnis aus Exception""" metadata = metadata or {} metadata.update({ 'exception_type': type(exception).__name__, 'traceback': traceback.format_exc() }) return cls( success=False, error_message=str(exception), error_code=code or type(exception).__name__, metadata=metadata, legacy_result=False ) @classmethod def from_legacy_boolean(cls, result: bool, success_data: Any = None, error_message: str = None): """Konvertiert legacy boolean zu OperationResult""" if result: return cls.success_result(data=success_data, legacy_result=result) else: return cls.error_result( message=error_message or "Operation failed", legacy_result=result ) @classmethod def from_legacy_dict(cls, result: Dict[str, Any]): """Konvertiert legacy dict zu OperationResult""" success = result.get('success', False) if success: return cls.success_result( data=result.get('data'), metadata=result.get('metadata', {}), legacy_result=result ) else: return cls.error_result( message=result.get('error', 'Operation failed'), code=result.get('error_code'), metadata=result.get('metadata', {}), legacy_result=result ) def is_success(self) -> bool: """Prüft ob Operation erfolgreich war""" return self.success def is_error(self) -> bool: """Prüft ob Operation fehlgeschlagen ist""" return not self.success def get_legacy_result(self) -> Any: """Gibt das ursprüngliche Result-Format zurück für backward compatibility""" return self.legacy_result def to_dict(self) -> Dict[str, Any]: """Konvertiert zu Dictionary für API/JSON Serialisierung""" result = { 'success': self.success, 'timestamp': self.timestamp.isoformat() if self.timestamp else None } if self.data is not None: result['data'] = self.data if self.error_message: result['error'] = self.error_message if self.error_code: result['error_code'] = self.error_code if self.metadata: result['metadata'] = self.metadata return result def to_legacy_dict(self) -> Dict[str, Any]: """Konvertiert zu legacy dict format""" return { 'success': self.success, 'data': self.data, 'error': self.error_message, 'error_code': self.error_code, 'metadata': self.metadata } def __bool__(self) -> bool: """Ermöglicht if result: syntax""" return self.success def __str__(self) -> str: if self.success: return f"Success: {self.data}" else: return f"Error: {self.error_message} ({self.error_code})" class ResultWrapper: """ Utility-Klasse für backward-compatible Wrapping von bestehenden Methoden """ @staticmethod def wrap_boolean_method(method, *args, **kwargs) -> OperationResult: """Wrapper für bestehende boolean-Methoden""" try: success = method(*args, **kwargs) return OperationResult.from_legacy_boolean( result=success, success_data=success, error_message="Operation failed" if not success else None ) except Exception as e: return OperationResult.from_exception(e) @staticmethod def wrap_dict_method(method, *args, **kwargs) -> OperationResult: """Wrapper für bestehende dict-Methoden""" try: result = method(*args, **kwargs) if isinstance(result, dict): return OperationResult.from_legacy_dict(result) else: return OperationResult.success_result(data=result, legacy_result=result) except Exception as e: return OperationResult.from_exception(e) @staticmethod def wrap_any_method(method, *args, **kwargs) -> OperationResult: """Universal wrapper für beliebige Methoden""" try: result = method(*args, **kwargs) if isinstance(result, bool): return OperationResult.from_legacy_boolean(result) elif isinstance(result, dict) and 'success' in result: return OperationResult.from_legacy_dict(result) elif result is None: return OperationResult.error_result("Method returned None", legacy_result=result) else: return OperationResult.success_result(data=result, legacy_result=result) except Exception as e: return OperationResult.from_exception(e) # Error Codes für häufige Fehlertypen class CommonErrorCodes: """Häufig verwendete Fehlercodes""" # Instagram spezifisch CAPTCHA_REQUIRED = "CAPTCHA_REQUIRED" EMAIL_TIMEOUT = "EMAIL_TIMEOUT" SMS_NOT_IMPLEMENTED = "SMS_NOT_IMPLEMENTED" USERNAME_TAKEN = "USERNAME_TAKEN" SELECTOR_NOT_FOUND = "SELECTOR_NOT_FOUND" BIRTHDAY_SELECTOR_FAILED = "BIRTHDAY_SELECTOR_FAILED" # Allgemein PROXY_ERROR = "PROXY_ERROR" RATE_LIMITED = "RATE_LIMITED" NETWORK_TIMEOUT = "NETWORK_TIMEOUT" BROWSER_ERROR = "BROWSER_ERROR" # Fingerprint spezifisch FINGERPRINT_GENERATION_FAILED = "FINGERPRINT_GENERATION_FAILED" FINGERPRINT_RACE_CONDITION = "FINGERPRINT_RACE_CONDITION" FINGERPRINT_NOT_FOUND = "FINGERPRINT_NOT_FOUND" # Session spezifisch SESSION_EXPIRED = "SESSION_EXPIRED" SESSION_INVALID = "SESSION_INVALID" SESSION_SAVE_FAILED = "SESSION_SAVE_FAILED"