unrealon 1.1.5__py3-none-any.whl → 2.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unrealon-1.1.5.dist-info/licenses → unrealon-2.0.4.dist-info}/LICENSE +1 -1
- unrealon-2.0.4.dist-info/METADATA +491 -0
- unrealon-2.0.4.dist-info/RECORD +129 -0
- {unrealon-1.1.5.dist-info → unrealon-2.0.4.dist-info}/WHEEL +2 -1
- unrealon-2.0.4.dist-info/entry_points.txt +3 -0
- unrealon-2.0.4.dist-info/top_level.txt +3 -0
- unrealon_browser/__init__.py +5 -2
- unrealon_browser/cli/browser_cli.py +18 -9
- unrealon_browser/cli/interactive_mode.py +18 -7
- unrealon_browser/core/browser_manager.py +76 -13
- unrealon_browser/dto/__init__.py +21 -0
- unrealon_browser/dto/bot_detection.py +175 -0
- unrealon_browser/dto/models/config.py +14 -1
- unrealon_browser/managers/__init__.py +4 -1
- unrealon_browser/managers/logger_bridge.py +3 -6
- unrealon_browser/managers/page_wait_manager.py +198 -0
- unrealon_browser/stealth/__init__.py +27 -0
- unrealon_browser/stealth/bypass_techniques.pyc +0 -0
- unrealon_browser/stealth/manager.pyc +0 -0
- unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
- unrealon_browser/stealth/playwright_stealth.pyc +0 -0
- unrealon_browser/stealth/scanner_tester.pyc +0 -0
- unrealon_browser/stealth/undetected_chrome.pyc +0 -0
- unrealon_core/__init__.py +160 -0
- unrealon_core/config/__init__.py +16 -0
- unrealon_core/config/environment.py +98 -0
- unrealon_core/config/urls.py +93 -0
- unrealon_core/enums/__init__.py +24 -0
- unrealon_core/enums/status.py +216 -0
- unrealon_core/enums/types.py +240 -0
- unrealon_core/error_handling/__init__.py +45 -0
- unrealon_core/error_handling/circuit_breaker.py +292 -0
- unrealon_core/error_handling/error_context.py +324 -0
- unrealon_core/error_handling/recovery.py +371 -0
- unrealon_core/error_handling/retry.py +268 -0
- unrealon_core/exceptions/__init__.py +46 -0
- unrealon_core/exceptions/base.py +292 -0
- unrealon_core/exceptions/communication.py +22 -0
- unrealon_core/exceptions/driver.py +11 -0
- unrealon_core/exceptions/proxy.py +11 -0
- unrealon_core/exceptions/task.py +12 -0
- unrealon_core/exceptions/validation.py +17 -0
- unrealon_core/models/__init__.py +98 -0
- unrealon_core/models/arq_context.py +252 -0
- unrealon_core/models/arq_responses.py +125 -0
- unrealon_core/models/base.py +291 -0
- unrealon_core/models/bridge_stats.py +58 -0
- unrealon_core/models/communication.py +39 -0
- unrealon_core/models/config.py +47 -0
- unrealon_core/models/connection_stats.py +47 -0
- unrealon_core/models/driver.py +30 -0
- unrealon_core/models/driver_details.py +98 -0
- unrealon_core/models/logging.py +28 -0
- unrealon_core/models/task.py +21 -0
- unrealon_core/models/typed_responses.py +210 -0
- unrealon_core/models/websocket/__init__.py +91 -0
- unrealon_core/models/websocket/base.py +49 -0
- unrealon_core/models/websocket/config.py +200 -0
- unrealon_core/models/websocket/driver.py +215 -0
- unrealon_core/models/websocket/errors.py +138 -0
- unrealon_core/models/websocket/heartbeat.py +100 -0
- unrealon_core/models/websocket/logging.py +261 -0
- unrealon_core/models/websocket/proxy.py +496 -0
- unrealon_core/models/websocket/tasks.py +275 -0
- unrealon_core/models/websocket/utils.py +153 -0
- unrealon_core/models/websocket_session.py +144 -0
- unrealon_core/monitoring/__init__.py +43 -0
- unrealon_core/monitoring/alerts.py +398 -0
- unrealon_core/monitoring/dashboard.py +307 -0
- unrealon_core/monitoring/health_check.py +354 -0
- unrealon_core/monitoring/metrics.py +352 -0
- unrealon_core/utils/__init__.py +11 -0
- unrealon_core/utils/time.py +61 -0
- unrealon_core/version.py +219 -0
- unrealon_driver/__init__.py +88 -50
- unrealon_driver/core_module/__init__.py +34 -0
- unrealon_driver/core_module/base.py +184 -0
- unrealon_driver/core_module/config.py +30 -0
- unrealon_driver/core_module/event_manager.py +127 -0
- unrealon_driver/core_module/protocols.py +98 -0
- unrealon_driver/core_module/registry.py +146 -0
- unrealon_driver/decorators/__init__.py +15 -0
- unrealon_driver/decorators/retry.py +117 -0
- unrealon_driver/decorators/schedule.py +137 -0
- unrealon_driver/decorators/task.py +61 -0
- unrealon_driver/decorators/timing.py +132 -0
- unrealon_driver/driver/__init__.py +20 -0
- unrealon_driver/driver/communication/__init__.py +10 -0
- unrealon_driver/driver/communication/session.py +203 -0
- unrealon_driver/driver/communication/websocket_client.py +197 -0
- unrealon_driver/driver/core/__init__.py +10 -0
- unrealon_driver/driver/core/config.py +85 -0
- unrealon_driver/driver/core/driver.py +221 -0
- unrealon_driver/driver/factory/__init__.py +9 -0
- unrealon_driver/driver/factory/manager_factory.py +130 -0
- unrealon_driver/driver/lifecycle/__init__.py +11 -0
- unrealon_driver/driver/lifecycle/daemon.py +76 -0
- unrealon_driver/driver/lifecycle/initialization.py +97 -0
- unrealon_driver/driver/lifecycle/shutdown.py +48 -0
- unrealon_driver/driver/monitoring/__init__.py +9 -0
- unrealon_driver/driver/monitoring/health.py +63 -0
- unrealon_driver/driver/utilities/__init__.py +10 -0
- unrealon_driver/driver/utilities/logging.py +51 -0
- unrealon_driver/driver/utilities/serialization.py +61 -0
- unrealon_driver/managers/__init__.py +32 -0
- unrealon_driver/managers/base.py +174 -0
- unrealon_driver/managers/browser.py +98 -0
- unrealon_driver/managers/cache.py +116 -0
- unrealon_driver/managers/http.py +107 -0
- unrealon_driver/managers/logger.py +286 -0
- unrealon_driver/managers/proxy.py +99 -0
- unrealon_driver/managers/registry.py +87 -0
- unrealon_driver/managers/threading.py +54 -0
- unrealon_driver/managers/update.py +107 -0
- unrealon_driver/utils/__init__.py +9 -0
- unrealon_driver/utils/time.py +10 -0
- unrealon/__init__.py +0 -40
- unrealon-1.1.5.dist-info/METADATA +0 -621
- unrealon-1.1.5.dist-info/RECORD +0 -54
- unrealon-1.1.5.dist-info/entry_points.txt +0 -9
- unrealon_browser/managers/stealth.py +0 -388
- unrealon_driver/exceptions.py +0 -33
- unrealon_driver/html_analyzer/__init__.py +0 -32
- unrealon_driver/html_analyzer/cleaner.py +0 -657
- unrealon_driver/html_analyzer/config.py +0 -64
- unrealon_driver/html_analyzer/manager.py +0 -247
- unrealon_driver/html_analyzer/models.py +0 -115
- unrealon_driver/html_analyzer/websocket_analyzer.py +0 -157
- unrealon_driver/models/__init__.py +0 -31
- unrealon_driver/models/websocket.py +0 -98
- unrealon_driver/parser/__init__.py +0 -36
- unrealon_driver/parser/cli_manager.py +0 -142
- unrealon_driver/parser/daemon_manager.py +0 -403
- unrealon_driver/parser/managers/__init__.py +0 -25
- unrealon_driver/parser/managers/config.py +0 -293
- unrealon_driver/parser/managers/error.py +0 -412
- unrealon_driver/parser/managers/result.py +0 -321
- unrealon_driver/parser/parser_manager.py +0 -458
- unrealon_driver/smart_logging/__init__.py +0 -24
- unrealon_driver/smart_logging/models.py +0 -44
- unrealon_driver/smart_logging/smart_logger.py +0 -406
- unrealon_driver/smart_logging/unified_logger.py +0 -525
- unrealon_driver/websocket/__init__.py +0 -31
- unrealon_driver/websocket/client.py +0 -249
- unrealon_driver/websocket/config.py +0 -188
- unrealon_driver/websocket/manager.py +0 -90
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""
|
|
2
|
+
UniversalDriver - Clean, modular driver orchestrator.
|
|
3
|
+
|
|
4
|
+
The main driver class that coordinates all components through a clean,
|
|
5
|
+
organized architecture with separated concerns.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional, List, Dict, Any, Callable
|
|
11
|
+
|
|
12
|
+
from .config import DriverConfig
|
|
13
|
+
from ..communication.websocket_client import WebSocketClient
|
|
14
|
+
from ..communication.session import DriverSession
|
|
15
|
+
from ..factory.manager_factory import ManagerFactory
|
|
16
|
+
from ..lifecycle.initialization import DriverInitializer
|
|
17
|
+
from ..lifecycle.shutdown import DriverShutdown
|
|
18
|
+
from ..lifecycle.daemon import DaemonManager
|
|
19
|
+
from ..monitoring.health import HealthMonitor
|
|
20
|
+
from ..utilities.logging import LoggingUtility
|
|
21
|
+
from ..utilities.serialization import SerializationUtility
|
|
22
|
+
|
|
23
|
+
from ...managers import (
|
|
24
|
+
LoggerManager, HttpManager, BrowserManager, CacheManager,
|
|
25
|
+
ProxyManager, ThreadManager, UpdateManager, ManagerRegistry
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from ...core_module import (
|
|
29
|
+
EventManager,
|
|
30
|
+
ModuleRegistry
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from ...decorators import task, retry, schedule, timing
|
|
34
|
+
|
|
35
|
+
logger = logging.getLogger(__name__)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class UniversalDriver:
|
|
39
|
+
"""
|
|
40
|
+
Universal Driver - Clean orchestrator for all parsing operations.
|
|
41
|
+
|
|
42
|
+
Key Features:
|
|
43
|
+
- Zero-config initialization with sensible defaults
|
|
44
|
+
- Modular manager system (HTTP, Browser, Cache, etc.)
|
|
45
|
+
- WebSocket communication for RPC and logging
|
|
46
|
+
- Graceful shutdown with signal handling
|
|
47
|
+
- Built-in utilities for common operations
|
|
48
|
+
- Decorator-based task registration
|
|
49
|
+
|
|
50
|
+
Usage:
|
|
51
|
+
# Basic usage
|
|
52
|
+
config = DriverConfig.for_development("my_parser")
|
|
53
|
+
driver = UniversalDriver(config)
|
|
54
|
+
await driver.initialize()
|
|
55
|
+
|
|
56
|
+
# Daemon mode with RPC
|
|
57
|
+
await driver.run_daemon_mode()
|
|
58
|
+
|
|
59
|
+
# Standalone mode
|
|
60
|
+
await driver.initialize()
|
|
61
|
+
# ... your parsing logic
|
|
62
|
+
await driver.shutdown()
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, config: DriverConfig):
|
|
66
|
+
"""Initialize UniversalDriver with configuration."""
|
|
67
|
+
self.config = config
|
|
68
|
+
self.driver_id = config.name
|
|
69
|
+
self.is_initialized = False
|
|
70
|
+
self.capabilities: List[str] = []
|
|
71
|
+
|
|
72
|
+
# Core components
|
|
73
|
+
self.websocket_client: Optional[WebSocketClient] = None
|
|
74
|
+
self.session: Optional[DriverSession] = None
|
|
75
|
+
|
|
76
|
+
# Manager system (initialized by factory)
|
|
77
|
+
self.manager_registry: Optional[ManagerRegistry] = None
|
|
78
|
+
self.logger_manager: Optional[LoggerManager] = None
|
|
79
|
+
self.http: Optional[HttpManager] = None
|
|
80
|
+
self.browser: Optional[BrowserManager] = None
|
|
81
|
+
self.cache: Optional[CacheManager] = None
|
|
82
|
+
self.proxy: Optional[ProxyManager] = None
|
|
83
|
+
self.threading: Optional[ThreadManager] = None
|
|
84
|
+
self.update: Optional[UpdateManager] = None
|
|
85
|
+
|
|
86
|
+
# Module system
|
|
87
|
+
self.event_manager = EventManager()
|
|
88
|
+
self.module_registry = ModuleRegistry(self.event_manager)
|
|
89
|
+
|
|
90
|
+
# Utilities
|
|
91
|
+
self._logging_util = LoggingUtility(self.driver_id)
|
|
92
|
+
|
|
93
|
+
# Decorators (exposed as instance methods for convenience)
|
|
94
|
+
self.task = task
|
|
95
|
+
self.retry = retry
|
|
96
|
+
self.schedule = schedule
|
|
97
|
+
self.timing = timing
|
|
98
|
+
|
|
99
|
+
# Setup managers using factory
|
|
100
|
+
self._setup_components()
|
|
101
|
+
|
|
102
|
+
def _setup_components(self):
|
|
103
|
+
"""Setup all driver components."""
|
|
104
|
+
# Initialize managers using factory
|
|
105
|
+
self.manager_registry = ManagerFactory.setup_managers(self)
|
|
106
|
+
|
|
107
|
+
# Update logging utility with manager
|
|
108
|
+
self._logging_util.logger_manager = self.logger_manager
|
|
109
|
+
|
|
110
|
+
logger.debug(f"UniversalDriver components initialized: {self.driver_id}")
|
|
111
|
+
|
|
112
|
+
# === Lifecycle Management ===
|
|
113
|
+
|
|
114
|
+
async def initialize(self, capabilities: List[str] = []) -> bool:
|
|
115
|
+
"""
|
|
116
|
+
Initialize driver with all components.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
capabilities: List of driver capabilities
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
True if initialization successful
|
|
123
|
+
"""
|
|
124
|
+
return await DriverInitializer.initialize_driver(self, capabilities)
|
|
125
|
+
|
|
126
|
+
async def shutdown(self):
|
|
127
|
+
"""Shutdown driver cleanly."""
|
|
128
|
+
await DriverShutdown.shutdown_driver(self)
|
|
129
|
+
|
|
130
|
+
async def run_daemon_mode(self, on_start_message: str = "Driver initialized, waiting for RPC tasks..."):
|
|
131
|
+
"""
|
|
132
|
+
Run driver in daemon mode with graceful shutdown handling.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
on_start_message: Message to display when daemon starts
|
|
136
|
+
"""
|
|
137
|
+
await DaemonManager.run_daemon_mode(self, on_start_message)
|
|
138
|
+
|
|
139
|
+
# === Task Registration ===
|
|
140
|
+
|
|
141
|
+
def register_task_handler(self, task_type: str, handler: Callable):
|
|
142
|
+
"""Register task handler for RPC tasks."""
|
|
143
|
+
if self.session:
|
|
144
|
+
self.session.register_task_handler(task_type, handler)
|
|
145
|
+
else:
|
|
146
|
+
logger.warning("No session available for task handler registration")
|
|
147
|
+
|
|
148
|
+
# === Health & Monitoring ===
|
|
149
|
+
|
|
150
|
+
async def health_check(self) -> Dict[str, Any]:
|
|
151
|
+
"""Get comprehensive health status."""
|
|
152
|
+
return await HealthMonitor.get_health_status(self)
|
|
153
|
+
|
|
154
|
+
def get_status(self) -> Dict[str, Any]:
|
|
155
|
+
"""Get basic driver status (synchronous)."""
|
|
156
|
+
return HealthMonitor.get_basic_status(self)
|
|
157
|
+
|
|
158
|
+
# === Utilities ===
|
|
159
|
+
|
|
160
|
+
def save_results_to_file(self, data: dict, filename: str, results_dir: Optional[str] = None) -> Path:
|
|
161
|
+
"""
|
|
162
|
+
Save parsing results to JSON file with automatic serialization.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
data: Data to save (can contain Pydantic models)
|
|
166
|
+
filename: Base filename (without extension)
|
|
167
|
+
results_dir: Directory to save to (default: ./data/results)
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Path to saved file
|
|
171
|
+
"""
|
|
172
|
+
return SerializationUtility.save_results_to_file(data, filename, results_dir)
|
|
173
|
+
|
|
174
|
+
# === Logging Methods ===
|
|
175
|
+
|
|
176
|
+
def log(self, level: str, message: str, context: Optional[Dict[str, Any]] = None):
|
|
177
|
+
"""Log message through logger manager."""
|
|
178
|
+
self._logging_util.log(level, message, context)
|
|
179
|
+
|
|
180
|
+
def debug(self, message: str, context: Optional[Dict[str, Any]] = None):
|
|
181
|
+
"""Log debug message."""
|
|
182
|
+
self._logging_util.debug(message, context)
|
|
183
|
+
|
|
184
|
+
def info(self, message: str, context: Optional[Dict[str, Any]] = None):
|
|
185
|
+
"""Log info message."""
|
|
186
|
+
self._logging_util.info(message, context)
|
|
187
|
+
|
|
188
|
+
def warning(self, message: str, context: Optional[Dict[str, Any]] = None):
|
|
189
|
+
"""Log warning message."""
|
|
190
|
+
self._logging_util.warning(message, context)
|
|
191
|
+
|
|
192
|
+
def error(self, message: str, context: Optional[Dict[str, Any]] = None):
|
|
193
|
+
"""Log error message."""
|
|
194
|
+
self._logging_util.error(message, context)
|
|
195
|
+
|
|
196
|
+
def critical(self, message: str, context: Optional[Dict[str, Any]] = None):
|
|
197
|
+
"""Log critical message."""
|
|
198
|
+
self._logging_util.critical(message, context)
|
|
199
|
+
|
|
200
|
+
# === Convenience Properties ===
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def is_daemon_mode(self) -> bool:
|
|
204
|
+
"""Check if driver is running in daemon mode."""
|
|
205
|
+
return self.session is not None
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def is_connected(self) -> bool:
|
|
209
|
+
"""Check if WebSocket is connected."""
|
|
210
|
+
return self.websocket_client is not None and self.websocket_client.is_connected
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def manager_count(self) -> int:
|
|
214
|
+
"""Get number of active managers."""
|
|
215
|
+
return len(self.manager_registry.managers) if self.manager_registry else 0
|
|
216
|
+
|
|
217
|
+
def __repr__(self) -> str:
|
|
218
|
+
"""String representation of driver."""
|
|
219
|
+
status = "initialized" if self.is_initialized else "not initialized"
|
|
220
|
+
mode = "daemon" if self.is_daemon_mode else "standalone"
|
|
221
|
+
return f"UniversalDriver(id='{self.driver_id}', status='{status}', mode='{mode}')"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manager Factory - Setup and configuration of all managers.
|
|
3
|
+
|
|
4
|
+
Handles the creation and configuration of manager components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from ...managers import (
|
|
11
|
+
LoggerManager, HttpManager, BrowserManager, CacheManager,
|
|
12
|
+
ProxyManager, ThreadManager, UpdateManager, ManagerRegistry
|
|
13
|
+
)
|
|
14
|
+
from ...managers.logger import LoggerManagerConfig
|
|
15
|
+
from ...managers.http import HttpManagerConfig
|
|
16
|
+
from ...managers.browser import BrowserManagerConfig
|
|
17
|
+
from ...managers.cache import CacheManagerConfig
|
|
18
|
+
from ...managers.proxy import ProxyManagerConfig
|
|
19
|
+
from ...managers.threading import ThreadManagerConfig
|
|
20
|
+
from ...managers.update import UpdateManagerConfig
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from ..core.driver import UniversalDriver
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ManagerFactory:
|
|
29
|
+
"""Factory for creating and configuring manager components."""
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def setup_managers(driver: 'UniversalDriver') -> ManagerRegistry:
|
|
33
|
+
"""
|
|
34
|
+
Setup all managers with configurations.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
driver: UniversalDriver instance
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Configured ManagerRegistry
|
|
41
|
+
"""
|
|
42
|
+
# Create registry
|
|
43
|
+
manager_registry = ManagerRegistry()
|
|
44
|
+
|
|
45
|
+
# Setup each manager
|
|
46
|
+
ManagerFactory._setup_logger_manager(driver, manager_registry)
|
|
47
|
+
ManagerFactory._setup_http_manager(driver, manager_registry)
|
|
48
|
+
ManagerFactory._setup_browser_manager(driver, manager_registry)
|
|
49
|
+
ManagerFactory._setup_cache_manager(driver, manager_registry)
|
|
50
|
+
ManagerFactory._setup_proxy_manager(driver, manager_registry)
|
|
51
|
+
ManagerFactory._setup_threading_manager(driver, manager_registry)
|
|
52
|
+
ManagerFactory._setup_update_manager(driver, manager_registry)
|
|
53
|
+
|
|
54
|
+
logger.debug(f"Managers setup complete for driver: {driver.driver_id}")
|
|
55
|
+
return manager_registry
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _setup_logger_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
59
|
+
"""Setup logger manager."""
|
|
60
|
+
logger_config = LoggerManagerConfig(
|
|
61
|
+
enabled=True,
|
|
62
|
+
log_file=driver.config.log_file,
|
|
63
|
+
log_level=driver.config.log_level,
|
|
64
|
+
driver_id=driver.driver_id,
|
|
65
|
+
timeout=driver.config.websocket_timeout
|
|
66
|
+
)
|
|
67
|
+
driver.logger_manager = LoggerManager(logger_config)
|
|
68
|
+
registry.register(driver.logger_manager)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def _setup_http_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
72
|
+
"""Setup HTTP manager."""
|
|
73
|
+
http_config = HttpManagerConfig(
|
|
74
|
+
enabled=True,
|
|
75
|
+
timeout=driver.config.http_timeout,
|
|
76
|
+
max_retries=driver.config.max_retries
|
|
77
|
+
)
|
|
78
|
+
driver.http = HttpManager(http_config)
|
|
79
|
+
registry.register(driver.http)
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def _setup_browser_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
83
|
+
"""Setup browser manager."""
|
|
84
|
+
browser_config = BrowserManagerConfig(
|
|
85
|
+
enabled=True,
|
|
86
|
+
headless=driver.config.browser_headless,
|
|
87
|
+
timeout=driver.config.browser_timeout,
|
|
88
|
+
parser_name=driver.driver_id
|
|
89
|
+
)
|
|
90
|
+
driver.browser = BrowserManager(browser_config)
|
|
91
|
+
registry.register(driver.browser)
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def _setup_cache_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
95
|
+
"""Setup cache manager."""
|
|
96
|
+
cache_config = CacheManagerConfig(
|
|
97
|
+
enabled=driver.config.cache_enabled,
|
|
98
|
+
default_ttl=driver.config.cache_ttl
|
|
99
|
+
)
|
|
100
|
+
driver.cache = CacheManager(cache_config)
|
|
101
|
+
registry.register(driver.cache)
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def _setup_proxy_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
105
|
+
"""Setup proxy manager."""
|
|
106
|
+
proxy_config = ProxyManagerConfig(
|
|
107
|
+
enabled=driver.config.proxy_enabled,
|
|
108
|
+
rotation_interval=driver.config.proxy_rotation_interval
|
|
109
|
+
)
|
|
110
|
+
driver.proxy = ProxyManager(proxy_config)
|
|
111
|
+
registry.register(driver.proxy)
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _setup_threading_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
115
|
+
"""Setup threading manager."""
|
|
116
|
+
threading_config = ThreadManagerConfig(
|
|
117
|
+
enabled=True,
|
|
118
|
+
max_workers=driver.config.max_workers
|
|
119
|
+
)
|
|
120
|
+
driver.threading = ThreadManager(threading_config)
|
|
121
|
+
registry.register(driver.threading)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def _setup_update_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
|
|
125
|
+
"""Setup update manager."""
|
|
126
|
+
update_config = UpdateManagerConfig(
|
|
127
|
+
enabled=True
|
|
128
|
+
)
|
|
129
|
+
driver.update = UpdateManager(update_config)
|
|
130
|
+
registry.register(driver.update)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Driver lifecycle management.
|
|
3
|
+
|
|
4
|
+
Handles initialization, shutdown, and daemon mode operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .initialization import DriverInitializer
|
|
8
|
+
from .shutdown import DriverShutdown
|
|
9
|
+
from .daemon import DaemonManager
|
|
10
|
+
|
|
11
|
+
__all__ = ["DriverInitializer", "DriverShutdown", "DaemonManager"]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Daemon mode management.
|
|
3
|
+
|
|
4
|
+
Handles running the driver in daemon mode with graceful shutdown.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import logging
|
|
9
|
+
import signal
|
|
10
|
+
import sys
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from .initialization import DriverInitializer
|
|
14
|
+
from .shutdown import DriverShutdown
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from ..core.driver import UniversalDriver
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DaemonManager:
|
|
23
|
+
"""Manages daemon mode operations."""
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
async def run_daemon_mode(driver: 'UniversalDriver', on_start_message: str = "Driver initialized, waiting for RPC tasks..."):
|
|
27
|
+
"""
|
|
28
|
+
Run driver in daemon mode with graceful shutdown handling.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
driver: UniversalDriver instance
|
|
32
|
+
on_start_message: Message to display when daemon starts
|
|
33
|
+
"""
|
|
34
|
+
# Flag for graceful shutdown
|
|
35
|
+
shutdown_event = asyncio.Event()
|
|
36
|
+
|
|
37
|
+
def signal_handler():
|
|
38
|
+
"""Handle shutdown signals gracefully."""
|
|
39
|
+
logger.info("Shutdown signal received")
|
|
40
|
+
shutdown_event.set()
|
|
41
|
+
|
|
42
|
+
# Register signal handlers
|
|
43
|
+
if sys.platform != "win32":
|
|
44
|
+
loop = asyncio.get_running_loop()
|
|
45
|
+
for sig in (signal.SIGTERM, signal.SIGINT):
|
|
46
|
+
loop.add_signal_handler(sig, signal_handler)
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
# Initialize driver with capabilities
|
|
50
|
+
success = await DriverInitializer.initialize_driver(driver, driver.capabilities)
|
|
51
|
+
if not success:
|
|
52
|
+
raise RuntimeError("Driver initialization failed")
|
|
53
|
+
|
|
54
|
+
# Call on_start hook if available
|
|
55
|
+
if hasattr(driver, 'on_start') and callable(driver.on_start):
|
|
56
|
+
await driver.on_start()
|
|
57
|
+
|
|
58
|
+
logger.info(on_start_message)
|
|
59
|
+
|
|
60
|
+
# Keep running until shutdown signal
|
|
61
|
+
await shutdown_event.wait()
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
logger.error(f"Daemon mode error: {e}")
|
|
65
|
+
raise
|
|
66
|
+
finally:
|
|
67
|
+
# Always shutdown cleanly
|
|
68
|
+
try:
|
|
69
|
+
# Call on_shutdown hook if available
|
|
70
|
+
if hasattr(driver, 'on_shutdown') and callable(driver.on_shutdown):
|
|
71
|
+
await driver.on_shutdown()
|
|
72
|
+
|
|
73
|
+
await DriverShutdown.shutdown_driver(driver)
|
|
74
|
+
logger.info("Driver shutdown complete")
|
|
75
|
+
except Exception as e:
|
|
76
|
+
logger.error(f"Error during shutdown: {e}")
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Driver initialization logic.
|
|
3
|
+
|
|
4
|
+
Handles the setup and initialization of all driver components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import List, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from ..core.config import DriverMode
|
|
11
|
+
from ..communication.websocket_client import WebSocketClient
|
|
12
|
+
from ..communication.session import DriverSession
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from ..core.driver import UniversalDriver
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DriverInitializer:
|
|
21
|
+
"""Handles driver initialization process."""
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
async def initialize_driver(driver: 'UniversalDriver', capabilities: List[str] = []) -> bool:
|
|
25
|
+
"""
|
|
26
|
+
Initialize driver with all components.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
driver: UniversalDriver instance
|
|
30
|
+
capabilities: List of driver capabilities
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
True if initialization successful
|
|
34
|
+
"""
|
|
35
|
+
# Store capabilities
|
|
36
|
+
driver.capabilities = capabilities
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
logger.info(f"Initializing UniversalDriver: {driver.driver_id}")
|
|
40
|
+
|
|
41
|
+
# Initialize manager system
|
|
42
|
+
if not await driver.manager_registry.initialize_all():
|
|
43
|
+
logger.error("Manager initialization failed")
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
# Initialize module system
|
|
47
|
+
await driver.module_registry.initialize_all()
|
|
48
|
+
|
|
49
|
+
# Setup WebSocket and session
|
|
50
|
+
await DriverInitializer._setup_communication(driver, capabilities)
|
|
51
|
+
|
|
52
|
+
logger.info(f"UniversalDriver {driver.driver_id} initialized successfully")
|
|
53
|
+
driver.is_initialized = True
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.error(f"Driver initialization failed: {e}")
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
async def _setup_communication(driver: 'UniversalDriver', capabilities: List[str]):
|
|
62
|
+
"""Setup WebSocket client and session based on driver mode."""
|
|
63
|
+
# Get WebSocket URL from config (auto-detected)
|
|
64
|
+
websocket_url = driver.config.effective_websocket_url
|
|
65
|
+
|
|
66
|
+
# Setup WebSocket client if URL available
|
|
67
|
+
if websocket_url:
|
|
68
|
+
driver.websocket_client = WebSocketClient(
|
|
69
|
+
websocket_url,
|
|
70
|
+
driver.driver_id
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Set WebSocket client for logger (always for logging)
|
|
74
|
+
if driver.logger_manager:
|
|
75
|
+
driver.logger_manager.websocket_client = driver.websocket_client
|
|
76
|
+
|
|
77
|
+
# Only create RPC session in DAEMON mode
|
|
78
|
+
if driver.config.mode == DriverMode.DAEMON:
|
|
79
|
+
# Create session
|
|
80
|
+
driver.session = DriverSession(
|
|
81
|
+
driver.driver_id,
|
|
82
|
+
driver.websocket_client
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Start session with capabilities
|
|
86
|
+
if capabilities is not None:
|
|
87
|
+
if not await driver.session.start_session(capabilities):
|
|
88
|
+
logger.error("Session start failed")
|
|
89
|
+
raise RuntimeError("Session start failed")
|
|
90
|
+
else:
|
|
91
|
+
# In STANDALONE mode - try to connect WebSocket for logging (optional)
|
|
92
|
+
try:
|
|
93
|
+
await driver.websocket_client.connect()
|
|
94
|
+
logger.info("WebSocket connected for logging only (standalone mode)")
|
|
95
|
+
except Exception as e:
|
|
96
|
+
logger.warning(f"WebSocket connection failed in standalone mode (will use local logging): {e}")
|
|
97
|
+
# Continue without WebSocket - not critical in standalone mode
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Driver shutdown logic.
|
|
3
|
+
|
|
4
|
+
Handles clean shutdown of all driver components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..core.driver import UniversalDriver
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DriverShutdown:
|
|
17
|
+
"""Handles driver shutdown process."""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
async def shutdown_driver(driver: 'UniversalDriver'):
|
|
21
|
+
"""Shutdown driver cleanly."""
|
|
22
|
+
try:
|
|
23
|
+
logger.info(f"Shutting down UniversalDriver: {driver.driver_id}")
|
|
24
|
+
|
|
25
|
+
# Stop session
|
|
26
|
+
if driver.session:
|
|
27
|
+
await driver.session.stop_session()
|
|
28
|
+
|
|
29
|
+
# Disconnect WebSocket client
|
|
30
|
+
if driver.websocket_client:
|
|
31
|
+
await driver.websocket_client.disconnect()
|
|
32
|
+
|
|
33
|
+
# Stop event manager
|
|
34
|
+
await driver.event_manager.stop()
|
|
35
|
+
|
|
36
|
+
# Stop module system
|
|
37
|
+
await driver.module_registry.stop_all()
|
|
38
|
+
|
|
39
|
+
# Shutdown managers
|
|
40
|
+
await driver.manager_registry.shutdown_all()
|
|
41
|
+
|
|
42
|
+
logger.info(f"UniversalDriver {driver.driver_id} shutdown complete")
|
|
43
|
+
driver.is_initialized = False
|
|
44
|
+
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.error(f"Driver shutdown error: {e}")
|
|
47
|
+
# Still mark as not initialized even if shutdown failed
|
|
48
|
+
driver.is_initialized = False
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Health monitoring for driver components.
|
|
3
|
+
|
|
4
|
+
Provides health checks and status monitoring for the driver.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, Any, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..core.driver import UniversalDriver
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HealthMonitor:
|
|
17
|
+
"""Monitors driver health and provides status information."""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
async def get_health_status(driver: 'UniversalDriver') -> Dict[str, Any]:
|
|
21
|
+
"""Get comprehensive health status."""
|
|
22
|
+
try:
|
|
23
|
+
# Get manager health
|
|
24
|
+
manager_health = await driver.manager_registry.health_check_all()
|
|
25
|
+
|
|
26
|
+
# Get module health
|
|
27
|
+
module_health = await driver.module_registry.health_check_all()
|
|
28
|
+
|
|
29
|
+
# Get session status
|
|
30
|
+
session_status = None
|
|
31
|
+
if driver.session:
|
|
32
|
+
session_status = driver.session.get_status()
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
"driver_id": driver.driver_id,
|
|
36
|
+
"config": {
|
|
37
|
+
"mode": driver.config.mode.value,
|
|
38
|
+
"websocket_enabled": driver.config.websocket_url is not None
|
|
39
|
+
},
|
|
40
|
+
"managers": manager_health,
|
|
41
|
+
"modules": module_health,
|
|
42
|
+
"session": session_status
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.error(f"Health check failed: {e}")
|
|
47
|
+
return {
|
|
48
|
+
"driver_id": driver.driver_id,
|
|
49
|
+
"status": "error",
|
|
50
|
+
"error": str(e)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def get_basic_status(driver: 'UniversalDriver') -> Dict[str, Any]:
|
|
55
|
+
"""Get basic driver status (synchronous)."""
|
|
56
|
+
return {
|
|
57
|
+
"driver_id": driver.driver_id,
|
|
58
|
+
"is_initialized": driver.is_initialized,
|
|
59
|
+
"is_daemon_mode": driver.session is not None,
|
|
60
|
+
"is_connected": driver.websocket_client is not None and driver.websocket_client.is_connected,
|
|
61
|
+
"manager_count": len(driver.manager_registry.managers) if driver.manager_registry else 0,
|
|
62
|
+
"capabilities": driver.capabilities
|
|
63
|
+
}
|