Dieser Commit ist enthalten in:
Claude Project Manager
2026-01-18 18:15:34 +01:00
Ursprung 4e82d5ef8f
Commit a25a26a01a
47 geänderte Dateien mit 4756 neuen und 2956 gelöschten Zeilen

Datei anzeigen

@ -255,21 +255,7 @@ class BasePlatformController(QObject):
# Normale Verarbeitung
self.handle_account_created(result)
def stop_account_creation(self):
"""Stoppt die Account-Erstellung"""
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()
generator_tab.add_log(f"{self.platform_name}-Account-Erstellung wurde abgebrochen")
generator_tab.set_running(False)
generator_tab.set_progress(0)
# Forge-Dialog schließen falls vorhanden
if hasattr(self, 'forge_dialog') and self.forge_dialog:
self.forge_dialog.close()
self.forge_dialog = None
def handle_account_created(self, result):
"""
Verarbeitet erfolgreich erstellte Accounts.
@ -287,19 +273,14 @@ class BasePlatformController(QObject):
Diese Methode kann von Unterklassen überschrieben werden für spezielle Anforderungen.
Sie stellt sicher dass:
1. Der Process Guard freigegeben wird
2. Der Worker-Thread gestoppt wird
3. Die UI zurückgesetzt wird
4. Dialoge geschlossen werden
"""
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
self.logger.info("Guard freigegeben bei Stop (BaseController)")
1. Der Worker-Thread gestoppt wird (Worker gibt Guard frei mit release())
2. Die UI zurückgesetzt wird
3. Dialoge geschlossen werden
# Worker stoppen falls vorhanden
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
User-Abbruch zählt NICHT als Failure.
"""
# Worker stoppen falls vorhanden (Worker.stop() gibt Guard frei)
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()

Datei anzeigen

@ -8,19 +8,23 @@ from typing import Dict, Any, Optional
from utils.text_similarity import TextSimilarity
from domain.value_objects.browser_protection_style import BrowserProtectionStyle, ProtectionLevel
import traceback
import logging
import threading
logger = logging.getLogger(__name__)
class BaseAccountCreationWorkerThread(QThread):
"""Basis-Klasse für alle Platform Worker Threads"""
# Signals MÜSSEN identisch zu bestehenden sein
update_signal = pyqtSignal(str)
log_signal = pyqtSignal(str)
progress_signal = pyqtSignal(int)
finished_signal = pyqtSignal(dict)
error_signal = pyqtSignal(str)
def __init__(self, params: Dict[str, Any], platform_name: str,
def __init__(self, params: Dict[str, Any], platform_name: str,
session_controller: Optional[Any] = None,
generator_tab: Optional[Any] = None):
super().__init__()
@ -29,10 +33,19 @@ class BaseAccountCreationWorkerThread(QThread):
self.session_controller = session_controller
self.generator_tab = generator_tab
self.running = True
# Thread-Safety Lock für Guard-Flags
self._guard_lock = threading.Lock()
# Flag: Wurde der Worker durch User-Abbruch gestoppt?
self._was_cancelled = False
# Flag: Wurde Guard bereits vom Worker freigegeben?
self._guard_released = False
# TextSimilarity für robustes Fehler-Matching
self.text_similarity = TextSimilarity(default_threshold=0.8)
# Platform-spezifische Error-Patterns (überschreibbar)
self.error_interpretations = self.get_error_interpretations()
@ -209,10 +222,8 @@ class BaseAccountCreationWorkerThread(QThread):
self.progress_signal.emit(0) # Reset progress on error
finally:
# Feature 5: Process Guard freigeben
from utils.process_guard import get_guard
guard = get_guard()
guard.end(success)
# Process Guard freigeben (thread-safe)
self._release_guard_if_needed(success)
def _interpret_error(self, error_message: str) -> str:
"""Interpretiert Fehler mit Fuzzy-Matching"""
@ -282,24 +293,47 @@ class BaseAccountCreationWorkerThread(QThread):
return save_result
def _release_guard_if_needed(self, success: bool = False, is_cancel: bool = False):
"""
Thread-safe Guard-Freigabe.
Args:
success: War der Prozess erfolgreich? (nur relevant bei end())
is_cancel: Wird von stop() aufgerufen? (erzwingt release())
"""
with self._guard_lock:
if self._guard_released:
# Bereits freigegeben - nichts zu tun
return
# Wenn von stop() aufgerufen, IMMER als Cancel markieren
if is_cancel:
self._was_cancelled = True
from utils.process_guard import get_guard
guard = get_guard()
if self._was_cancelled:
# User-Abbruch: release() zählt nicht als Failure
guard.release()
logger.info(f"{self.platform_name}: Guard released (User-Abbruch)")
else:
# Normale Beendigung: end() mit Erfolgs-Status
guard.end(success)
logger.info(f"{self.platform_name}: Guard ended (success={success})")
self._guard_released = True
def stop(self):
"""
Stoppt den Thread sauber mit Guard-Freigabe.
WICHTIG: Guard wird SOFORT freigegeben, da terminate() den finally-Block überspringt.
User-Abbruch wird mit release() behandelt (zählt NICHT als Failure).
"""
import logging
logger = logging.getLogger(__name__)
self.running = False
# Guard SOFORT freigeben bevor terminate()
# Grund: terminate() überspringt den finally-Block in run()
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
logger.info("Guard freigegeben bei Worker-Stop (vor terminate)")
# Guard thread-safe freigeben (is_cancel=True setzt _was_cancelled im Lock)
self._release_guard_if_needed(is_cancel=True)
# Jetzt Thread beenden
self.terminate()

Datei anzeigen

@ -307,15 +307,13 @@ class FacebookController(BasePlatformController):
self.forge_dialog = None
def stop_account_creation(self):
"""Stoppt die Facebook-Account-Erstellung mit Guard-Freigabe."""
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
self.logger.info("Guard freigegeben bei Facebook Stop")
"""
Stoppt die Facebook-Account-Erstellung.
# Worker stoppen
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
User-Abbruch zählt NICHT als Failure.
"""
# Worker stoppen (Worker.stop() gibt Guard frei mit release())
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()

Datei anzeigen

@ -198,17 +198,15 @@ class GmailController(BasePlatformController):
logger.info(f"[GMAIL] start_account_creation abgeschlossen")
def stop_account_creation(self):
"""Stoppt die laufende Account-Erstellung mit Guard-Freigabe"""
"""
Stoppt die Gmail-Account-Erstellung.
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
User-Abbruch zählt NICHT als Failure.
"""
logger.info("[GMAIL] Stoppe Account-Erstellung")
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
logger.info("Guard freigegeben bei Gmail Stop")
# Worker stoppen
# Worker stoppen (Worker.stop() gibt Guard frei mit release())
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
self.worker_thread.wait()

Datei anzeigen

@ -198,8 +198,9 @@ class InstagramController(BasePlatformController):
is_valid, error_msg = self.validate_inputs(params)
if not is_valid:
# Guard freigeben da Worker nicht gestartet wird
# release() statt end() - Validierungsfehler ist kein "echter" Failure
from utils.process_guard import get_guard
get_guard().end(success=False)
get_guard().release()
self.get_generator_tab().show_error(error_msg)
return
@ -213,8 +214,10 @@ class InstagramController(BasePlatformController):
# Schmiedeanimation-Dialog erstellen und anzeigen
parent_widget = generator_tab.window() # Hauptfenster als Parent
self.forge_dialog = ForgeAnimationDialog(parent_widget, "Instagram")
self.forge_dialog.cancel_clicked.connect(self.stop_account_creation)
self.forge_dialog.closed.connect(self.stop_account_creation)
# NUR cancel_clicked verbinden - closed wird durch close() in stop_account_creation
# getriggert und würde sonst zu Doppelaufrufen führen
self.forge_dialog.cancel_clicked.connect(self._on_user_cancel)
# Fensterposition vom Hauptfenster holen
if parent_widget:
@ -276,28 +279,35 @@ class InstagramController(BasePlatformController):
# Kritischer Fehler VOR Worker-Start → Guard freigeben!
logger.error(f"Fehler beim Start der Account-Erstellung: {e}", exc_info=True)
# release() - technischer Fehler vor Start ist kein User-Failure
from utils.process_guard import get_guard
get_guard().end(success=False)
get_guard().release()
# Dialog schließen falls vorhanden
if hasattr(self, 'forge_dialog') and self.forge_dialog:
self.forge_dialog.close()
self.forge_dialog = None
# UI zurücksetzen
generator_tab = self.get_generator_tab()
generator_tab.set_running(False)
generator_tab.show_error(f"Fehler beim Start: {str(e)}")
def stop_account_creation(self):
"""Stoppt die Instagram-Account-Erstellung mit Guard-Freigabe."""
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
self.logger.info("Guard freigegeben bei Instagram Stop")
def _on_user_cancel(self):
"""
Handler für User-Abbruch (Cancel-Button im Dialog).
Ruft stop_account_creation auf und verhindert Doppelaufrufe.
"""
self.stop_account_creation()
# Worker stoppen
def stop_account_creation(self):
"""
Stoppt die Instagram-Account-Erstellung.
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
Der Controller macht KEINE eigene Guard-Freigabe mehr.
"""
# Worker stoppen (Worker.stop() gibt Guard frei mit release())
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()

Datei anzeigen

@ -267,17 +267,28 @@ class MethodRotationMixin:
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
"""
# Handle both BrowserFingerprint objects and dictionaries
fingerprint_data = params.get('fingerprint')
fingerprint_id = None
if fingerprint_data:
if hasattr(fingerprint_data, 'fingerprint_id'):
# BrowserFingerprint object
fingerprint_id = fingerprint_data.fingerprint_id
elif isinstance(fingerprint_data, dict):
# Dictionary
fingerprint_id = fingerprint_data.get('fingerprint_id')
return RotationContext(
platform=self.platform_name.lower(),
account_id=params.get('account_id'),
fingerprint_id=params.get('fingerprint', {}).get('fingerprint_id'),
fingerprint_id=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),

Datei anzeigen

@ -131,15 +131,13 @@ class OkRuController(BasePlatformController):
self.forge_dialog.show()
def stop_account_creation(self):
"""Stoppt die OK.ru-Account-Erstellung mit Guard-Freigabe."""
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
self.logger.info("Guard freigegeben bei OK.ru Stop")
"""
Stoppt die OK.ru-Account-Erstellung.
# Worker stoppen
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
User-Abbruch zählt NICHT als Failure.
"""
# Worker stoppen (Worker.stop() gibt Guard frei mit release())
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()

Datei anzeigen

@ -273,15 +273,13 @@ class TikTokController(BasePlatformController):
self.forge_dialog.show()
def stop_account_creation(self):
"""Stoppt die TikTok-Account-Erstellung mit Guard-Freigabe."""
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
self.logger.info("Guard freigegeben bei TikTok Stop")
"""
Stoppt die TikTok-Account-Erstellung.
# Worker stoppen
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
User-Abbruch zählt NICHT als Failure.
"""
# Worker stoppen (Worker.stop() gibt Guard frei mit release())
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()

Datei anzeigen

@ -271,15 +271,13 @@ class XController(BasePlatformController):
self.forge_dialog.show()
def stop_account_creation(self):
"""Stoppt die X-Account-Erstellung mit Guard-Freigabe."""
# Guard-Freigabe (wichtig: VOR Worker-Stop)
from utils.process_guard import get_guard
guard = get_guard()
if guard.is_locked():
guard.end(success=False)
self.logger.info("Guard freigegeben bei X Stop")
"""
Stoppt die X-Account-Erstellung.
# Worker stoppen
WICHTIG: Guard-Freigabe erfolgt im Worker.stop() mit release().
User-Abbruch zählt NICHT als Failure.
"""
# Worker stoppen (Worker.stop() gibt Guard frei mit release())
if self.worker_thread and self.worker_thread.isRunning():
self.worker_thread.stop()
generator_tab = self.get_generator_tab()