unrealon 1.1.6__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.
Files changed (145) hide show
  1. {unrealon-1.1.6.dist-info/licenses → unrealon-2.0.4.dist-info}/LICENSE +1 -1
  2. unrealon-2.0.4.dist-info/METADATA +491 -0
  3. unrealon-2.0.4.dist-info/RECORD +129 -0
  4. {unrealon-1.1.6.dist-info → unrealon-2.0.4.dist-info}/WHEEL +2 -1
  5. unrealon-2.0.4.dist-info/entry_points.txt +3 -0
  6. unrealon-2.0.4.dist-info/top_level.txt +3 -0
  7. unrealon_browser/__init__.py +5 -6
  8. unrealon_browser/cli/browser_cli.py +18 -9
  9. unrealon_browser/cli/interactive_mode.py +13 -4
  10. unrealon_browser/core/browser_manager.py +29 -16
  11. unrealon_browser/dto/__init__.py +21 -0
  12. unrealon_browser/dto/bot_detection.py +175 -0
  13. unrealon_browser/dto/models/config.py +9 -3
  14. unrealon_browser/managers/__init__.py +1 -1
  15. unrealon_browser/managers/logger_bridge.py +1 -4
  16. unrealon_browser/stealth/__init__.py +27 -0
  17. unrealon_browser/stealth/bypass_techniques.pyc +0 -0
  18. unrealon_browser/stealth/manager.pyc +0 -0
  19. unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
  20. unrealon_browser/stealth/playwright_stealth.pyc +0 -0
  21. unrealon_browser/stealth/scanner_tester.pyc +0 -0
  22. unrealon_browser/stealth/undetected_chrome.pyc +0 -0
  23. unrealon_core/__init__.py +160 -0
  24. unrealon_core/config/__init__.py +16 -0
  25. unrealon_core/config/environment.py +98 -0
  26. unrealon_core/config/urls.py +93 -0
  27. unrealon_core/enums/__init__.py +24 -0
  28. unrealon_core/enums/status.py +216 -0
  29. unrealon_core/enums/types.py +240 -0
  30. unrealon_core/error_handling/__init__.py +45 -0
  31. unrealon_core/error_handling/circuit_breaker.py +292 -0
  32. unrealon_core/error_handling/error_context.py +324 -0
  33. unrealon_core/error_handling/recovery.py +371 -0
  34. unrealon_core/error_handling/retry.py +268 -0
  35. unrealon_core/exceptions/__init__.py +46 -0
  36. unrealon_core/exceptions/base.py +292 -0
  37. unrealon_core/exceptions/communication.py +22 -0
  38. unrealon_core/exceptions/driver.py +11 -0
  39. unrealon_core/exceptions/proxy.py +11 -0
  40. unrealon_core/exceptions/task.py +12 -0
  41. unrealon_core/exceptions/validation.py +17 -0
  42. unrealon_core/models/__init__.py +98 -0
  43. unrealon_core/models/arq_context.py +252 -0
  44. unrealon_core/models/arq_responses.py +125 -0
  45. unrealon_core/models/base.py +291 -0
  46. unrealon_core/models/bridge_stats.py +58 -0
  47. unrealon_core/models/communication.py +39 -0
  48. unrealon_core/models/config.py +47 -0
  49. unrealon_core/models/connection_stats.py +47 -0
  50. unrealon_core/models/driver.py +30 -0
  51. unrealon_core/models/driver_details.py +98 -0
  52. unrealon_core/models/logging.py +28 -0
  53. unrealon_core/models/task.py +21 -0
  54. unrealon_core/models/typed_responses.py +210 -0
  55. unrealon_core/models/websocket/__init__.py +91 -0
  56. unrealon_core/models/websocket/base.py +49 -0
  57. unrealon_core/models/websocket/config.py +200 -0
  58. unrealon_core/models/websocket/driver.py +215 -0
  59. unrealon_core/models/websocket/errors.py +138 -0
  60. unrealon_core/models/websocket/heartbeat.py +100 -0
  61. unrealon_core/models/websocket/logging.py +261 -0
  62. unrealon_core/models/websocket/proxy.py +496 -0
  63. unrealon_core/models/websocket/tasks.py +275 -0
  64. unrealon_core/models/websocket/utils.py +153 -0
  65. unrealon_core/models/websocket_session.py +144 -0
  66. unrealon_core/monitoring/__init__.py +43 -0
  67. unrealon_core/monitoring/alerts.py +398 -0
  68. unrealon_core/monitoring/dashboard.py +307 -0
  69. unrealon_core/monitoring/health_check.py +354 -0
  70. unrealon_core/monitoring/metrics.py +352 -0
  71. unrealon_core/utils/__init__.py +11 -0
  72. unrealon_core/utils/time.py +61 -0
  73. unrealon_core/version.py +219 -0
  74. unrealon_driver/__init__.py +90 -51
  75. unrealon_driver/core_module/__init__.py +34 -0
  76. unrealon_driver/core_module/base.py +184 -0
  77. unrealon_driver/core_module/config.py +30 -0
  78. unrealon_driver/core_module/event_manager.py +127 -0
  79. unrealon_driver/core_module/protocols.py +98 -0
  80. unrealon_driver/core_module/registry.py +146 -0
  81. unrealon_driver/decorators/__init__.py +15 -0
  82. unrealon_driver/decorators/retry.py +117 -0
  83. unrealon_driver/decorators/schedule.py +137 -0
  84. unrealon_driver/decorators/task.py +61 -0
  85. unrealon_driver/decorators/timing.py +132 -0
  86. unrealon_driver/driver/__init__.py +20 -0
  87. unrealon_driver/driver/communication/__init__.py +10 -0
  88. unrealon_driver/driver/communication/session.py +203 -0
  89. unrealon_driver/driver/communication/websocket_client.py +197 -0
  90. unrealon_driver/driver/core/__init__.py +10 -0
  91. unrealon_driver/driver/core/config.py +85 -0
  92. unrealon_driver/driver/core/driver.py +221 -0
  93. unrealon_driver/driver/factory/__init__.py +9 -0
  94. unrealon_driver/driver/factory/manager_factory.py +130 -0
  95. unrealon_driver/driver/lifecycle/__init__.py +11 -0
  96. unrealon_driver/driver/lifecycle/daemon.py +76 -0
  97. unrealon_driver/driver/lifecycle/initialization.py +97 -0
  98. unrealon_driver/driver/lifecycle/shutdown.py +48 -0
  99. unrealon_driver/driver/monitoring/__init__.py +9 -0
  100. unrealon_driver/driver/monitoring/health.py +63 -0
  101. unrealon_driver/driver/utilities/__init__.py +10 -0
  102. unrealon_driver/driver/utilities/logging.py +51 -0
  103. unrealon_driver/driver/utilities/serialization.py +61 -0
  104. unrealon_driver/managers/__init__.py +32 -0
  105. unrealon_driver/managers/base.py +174 -0
  106. unrealon_driver/managers/browser.py +98 -0
  107. unrealon_driver/managers/cache.py +116 -0
  108. unrealon_driver/managers/http.py +107 -0
  109. unrealon_driver/managers/logger.py +286 -0
  110. unrealon_driver/managers/proxy.py +99 -0
  111. unrealon_driver/managers/registry.py +87 -0
  112. unrealon_driver/managers/threading.py +54 -0
  113. unrealon_driver/managers/update.py +107 -0
  114. unrealon_driver/utils/__init__.py +9 -0
  115. unrealon_driver/utils/time.py +10 -0
  116. unrealon-1.1.6.dist-info/METADATA +0 -625
  117. unrealon-1.1.6.dist-info/RECORD +0 -55
  118. unrealon-1.1.6.dist-info/entry_points.txt +0 -9
  119. unrealon_browser/managers/stealth.py +0 -388
  120. unrealon_driver/README.md +0 -0
  121. unrealon_driver/exceptions.py +0 -33
  122. unrealon_driver/html_analyzer/__init__.py +0 -32
  123. unrealon_driver/html_analyzer/cleaner.py +0 -657
  124. unrealon_driver/html_analyzer/config.py +0 -64
  125. unrealon_driver/html_analyzer/manager.py +0 -247
  126. unrealon_driver/html_analyzer/models.py +0 -115
  127. unrealon_driver/html_analyzer/websocket_analyzer.py +0 -157
  128. unrealon_driver/models/__init__.py +0 -31
  129. unrealon_driver/models/websocket.py +0 -98
  130. unrealon_driver/parser/__init__.py +0 -36
  131. unrealon_driver/parser/cli_manager.py +0 -142
  132. unrealon_driver/parser/daemon_manager.py +0 -403
  133. unrealon_driver/parser/managers/__init__.py +0 -25
  134. unrealon_driver/parser/managers/config.py +0 -293
  135. unrealon_driver/parser/managers/error.py +0 -412
  136. unrealon_driver/parser/managers/result.py +0 -321
  137. unrealon_driver/parser/parser_manager.py +0 -458
  138. unrealon_driver/smart_logging/__init__.py +0 -24
  139. unrealon_driver/smart_logging/models.py +0 -44
  140. unrealon_driver/smart_logging/smart_logger.py +0 -406
  141. unrealon_driver/smart_logging/unified_logger.py +0 -525
  142. unrealon_driver/websocket/__init__.py +0 -31
  143. unrealon_driver/websocket/client.py +0 -249
  144. unrealon_driver/websocket/config.py +0 -188
  145. 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,9 @@
1
+ """
2
+ Factory pattern for driver components.
3
+
4
+ Handles setup and configuration of managers and other components.
5
+ """
6
+
7
+ from .manager_factory import ManagerFactory
8
+
9
+ __all__ = ["ManagerFactory"]
@@ -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,9 @@
1
+ """
2
+ Driver monitoring and health checks.
3
+
4
+ Provides health status and monitoring capabilities.
5
+ """
6
+
7
+ from .health import HealthMonitor
8
+
9
+ __all__ = ["HealthMonitor"]
@@ -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
+ }
@@ -0,0 +1,10 @@
1
+ """
2
+ Driver utilities.
3
+
4
+ Common utilities for logging, serialization, and result handling.
5
+ """
6
+
7
+ from .logging import LoggingUtility
8
+ from .serialization import SerializationUtility
9
+
10
+ __all__ = ["LoggingUtility", "SerializationUtility"]