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.
- {unrealon-1.1.6.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.6.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 -6
- unrealon_browser/cli/browser_cli.py +18 -9
- unrealon_browser/cli/interactive_mode.py +13 -4
- unrealon_browser/core/browser_manager.py +29 -16
- unrealon_browser/dto/__init__.py +21 -0
- unrealon_browser/dto/bot_detection.py +175 -0
- unrealon_browser/dto/models/config.py +9 -3
- unrealon_browser/managers/__init__.py +1 -1
- unrealon_browser/managers/logger_bridge.py +1 -4
- 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 +90 -51
- 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-1.1.6.dist-info/METADATA +0 -625
- unrealon-1.1.6.dist-info/RECORD +0 -55
- unrealon-1.1.6.dist-info/entry_points.txt +0 -9
- unrealon_browser/managers/stealth.py +0 -388
- unrealon_driver/README.md +0 -0
- 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,275 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task WebSocket Models.
|
|
3
|
+
|
|
4
|
+
Strictly typed models for task assignments and results.
|
|
5
|
+
No raw dictionaries - all data structures are Pydantic models.
|
|
6
|
+
|
|
7
|
+
Phase 2: Core Systems - WebSocket Bridge
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Optional, List, Union
|
|
11
|
+
from pydantic import Field, ConfigDict, field_validator, HttpUrl
|
|
12
|
+
|
|
13
|
+
from ..base import UnrealOnBaseModel
|
|
14
|
+
from .base import WebSocketMessage, MessageType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TaskParameters(UnrealOnBaseModel):
|
|
18
|
+
"""Task-specific parameters - strictly typed."""
|
|
19
|
+
|
|
20
|
+
model_config = ConfigDict(
|
|
21
|
+
validate_assignment=True,
|
|
22
|
+
extra="forbid"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
selectors: Optional[List[str]] = Field(
|
|
26
|
+
default=None,
|
|
27
|
+
description="CSS selectors for parsing"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
wait_for: Optional[str] = Field(
|
|
31
|
+
default=None,
|
|
32
|
+
description="Element to wait for before parsing"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
scroll_to_bottom: bool = Field(
|
|
36
|
+
default=False,
|
|
37
|
+
description="Whether to scroll to bottom"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
screenshot: bool = Field(
|
|
41
|
+
default=False,
|
|
42
|
+
description="Whether to take screenshot"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
user_agent: Optional[str] = Field(
|
|
46
|
+
default=None,
|
|
47
|
+
description="Custom user agent"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
headers: Optional[List[str]] = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="Custom headers as key:value pairs"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TaskMetadata(UnrealOnBaseModel):
|
|
57
|
+
"""Task metadata - strictly typed."""
|
|
58
|
+
|
|
59
|
+
model_config = ConfigDict(
|
|
60
|
+
validate_assignment=True,
|
|
61
|
+
extra="forbid"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
source: Optional[str] = Field(
|
|
65
|
+
default=None,
|
|
66
|
+
description="Task source system"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
batch_id: Optional[str] = Field(
|
|
70
|
+
default=None,
|
|
71
|
+
description="Batch identifier"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
user_id: Optional[str] = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description="User who created the task"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
tags: List[str] = Field(
|
|
80
|
+
default_factory=list,
|
|
81
|
+
description="Task tags"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class TaskAssignmentData(UnrealOnBaseModel):
|
|
86
|
+
"""Task assignment data payload - strictly typed."""
|
|
87
|
+
|
|
88
|
+
model_config = ConfigDict(
|
|
89
|
+
validate_assignment=True,
|
|
90
|
+
extra="forbid"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
task_id: str = Field(
|
|
94
|
+
min_length=1,
|
|
95
|
+
description="Unique task identifier"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
task_type: str = Field(
|
|
99
|
+
min_length=1,
|
|
100
|
+
description="Type of task to execute"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
url: HttpUrl = Field(
|
|
104
|
+
description="Target URL for the task"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
parameters: TaskParameters = Field(
|
|
108
|
+
default_factory=TaskParameters,
|
|
109
|
+
description="Task-specific parameters"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
priority: str = Field(
|
|
113
|
+
default="normal",
|
|
114
|
+
pattern=r"^(low|normal|high|urgent|critical)$",
|
|
115
|
+
description="Task priority level"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
timeout_seconds: float = Field(
|
|
119
|
+
default=300.0,
|
|
120
|
+
ge=30.0,
|
|
121
|
+
le=3600.0,
|
|
122
|
+
description="Task timeout in seconds"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
retry_count: int = Field(
|
|
126
|
+
default=3,
|
|
127
|
+
ge=0,
|
|
128
|
+
le=10,
|
|
129
|
+
description="Number of retries allowed"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
metadata: TaskMetadata = Field(
|
|
133
|
+
default_factory=TaskMetadata,
|
|
134
|
+
description="Additional task metadata"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class TaskAssignmentMessage(WebSocketMessage):
|
|
139
|
+
"""Task assignment message (Server → Driver)."""
|
|
140
|
+
|
|
141
|
+
model_config = ConfigDict(
|
|
142
|
+
validate_assignment=True,
|
|
143
|
+
extra="forbid"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
type: MessageType = Field(
|
|
147
|
+
default=MessageType.TASK_ASSIGN,
|
|
148
|
+
frozen=True
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
data: TaskAssignmentData = Field(
|
|
152
|
+
description="Task assignment data"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class TaskResultData(UnrealOnBaseModel):
|
|
157
|
+
"""Task result data - strictly typed."""
|
|
158
|
+
|
|
159
|
+
model_config = ConfigDict(
|
|
160
|
+
validate_assignment=True,
|
|
161
|
+
extra="forbid"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Basic fields
|
|
165
|
+
title: Optional[str] = Field(
|
|
166
|
+
default=None,
|
|
167
|
+
description="Extracted title"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
description: Optional[str] = Field(
|
|
171
|
+
default=None,
|
|
172
|
+
description="Extracted description"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
price: Optional[str] = Field(
|
|
176
|
+
default=None,
|
|
177
|
+
description="Extracted price"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
images: List[str] = Field(
|
|
181
|
+
default_factory=list,
|
|
182
|
+
description="Extracted image URLs"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
links: List[str] = Field(
|
|
186
|
+
default_factory=list,
|
|
187
|
+
description="Extracted links"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Custom fields for specific parsers
|
|
191
|
+
custom_fields: List[str] = Field(
|
|
192
|
+
default_factory=list,
|
|
193
|
+
description="Custom extracted fields as key:value pairs"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class TaskResultPayload(UnrealOnBaseModel):
|
|
198
|
+
"""Task result payload - strictly typed."""
|
|
199
|
+
|
|
200
|
+
model_config = ConfigDict(
|
|
201
|
+
validate_assignment=True,
|
|
202
|
+
extra="forbid"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
task_id: str = Field(
|
|
206
|
+
description="Task identifier"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
status: str = Field(
|
|
210
|
+
pattern=r"^(completed|failed|timeout|cancelled)$",
|
|
211
|
+
description="Task completion status"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
result: Optional[TaskResultData] = Field(
|
|
215
|
+
default=None,
|
|
216
|
+
description="Task result data (if successful)"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
error_message: Optional[str] = Field(
|
|
220
|
+
default=None,
|
|
221
|
+
description="Error message (if failed)"
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
error_code: Optional[str] = Field(
|
|
225
|
+
default=None,
|
|
226
|
+
description="Error code (if failed)"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
execution_time_seconds: float = Field(
|
|
230
|
+
default=0.0,
|
|
231
|
+
ge=0.0,
|
|
232
|
+
description="Task execution time in seconds"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
screenshot_url: Optional[str] = Field(
|
|
236
|
+
default=None,
|
|
237
|
+
description="Screenshot URL (if taken)"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
metadata: TaskMetadata = Field(
|
|
241
|
+
default_factory=TaskMetadata,
|
|
242
|
+
description="Additional result metadata"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
@field_validator('result')
|
|
246
|
+
@classmethod
|
|
247
|
+
def validate_result(cls, v: Optional[TaskResultData], info) -> Optional[TaskResultData]:
|
|
248
|
+
"""Validate result based on status."""
|
|
249
|
+
status = info.data.get('status')
|
|
250
|
+
|
|
251
|
+
if status == 'completed' and v is None:
|
|
252
|
+
raise ValueError("Result is required for completed tasks")
|
|
253
|
+
|
|
254
|
+
if status != 'completed' and v is not None:
|
|
255
|
+
raise ValueError("Result should be None for non-completed tasks")
|
|
256
|
+
|
|
257
|
+
return v
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class TaskResultMessage(WebSocketMessage):
|
|
261
|
+
"""Task result message (Driver → Server)."""
|
|
262
|
+
|
|
263
|
+
model_config = ConfigDict(
|
|
264
|
+
validate_assignment=True,
|
|
265
|
+
extra="forbid"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
type: MessageType = Field(
|
|
269
|
+
default=MessageType.TASK_RESULT,
|
|
270
|
+
frozen=True
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
data: TaskResultPayload = Field(
|
|
274
|
+
description="Task result data"
|
|
275
|
+
)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WebSocket Message Utilities.
|
|
3
|
+
|
|
4
|
+
Utility functions for creating WebSocket messages.
|
|
5
|
+
Strictly typed - no raw dictionaries.
|
|
6
|
+
|
|
7
|
+
Phase 2: Core Systems - WebSocket Bridge
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Optional, List
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from .errors import ErrorMessage, ErrorData, ErrorDetails, AckMessage, AckData
|
|
14
|
+
from ...utils.time import utc_now
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_error_message(
|
|
18
|
+
error_code: str,
|
|
19
|
+
error_message: str,
|
|
20
|
+
correlation_id: Optional[str] = None,
|
|
21
|
+
field_errors: Optional[List[str]] = None,
|
|
22
|
+
stack_trace: Optional[str] = None,
|
|
23
|
+
retry_after: Optional[int] = None
|
|
24
|
+
) -> ErrorMessage:
|
|
25
|
+
"""
|
|
26
|
+
Create an error message with strict typing.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
error_code: Error code identifier
|
|
30
|
+
error_message: Human-readable error message
|
|
31
|
+
correlation_id: ID of the message this is responding to
|
|
32
|
+
field_errors: List of field validation errors
|
|
33
|
+
stack_trace: Stack trace if available
|
|
34
|
+
retry_after: Retry after seconds if retryable
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Strictly typed ErrorMessage
|
|
38
|
+
"""
|
|
39
|
+
details = None
|
|
40
|
+
if field_errors or stack_trace:
|
|
41
|
+
details = ErrorDetails(
|
|
42
|
+
field_errors=field_errors or [],
|
|
43
|
+
stack_trace=stack_trace,
|
|
44
|
+
timestamp=utc_now().isoformat()
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
error_data = ErrorData(
|
|
48
|
+
error_code=error_code,
|
|
49
|
+
error_message=error_message,
|
|
50
|
+
details=details,
|
|
51
|
+
retry_after=retry_after
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return ErrorMessage(
|
|
55
|
+
correlation_id=correlation_id,
|
|
56
|
+
data=error_data
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def create_ack_message(
|
|
61
|
+
correlation_id: str,
|
|
62
|
+
message: Optional[str] = None,
|
|
63
|
+
processing_time_ms: Optional[float] = None
|
|
64
|
+
) -> AckMessage:
|
|
65
|
+
"""
|
|
66
|
+
Create an acknowledgment message with strict typing.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
correlation_id: ID of the message being acknowledged
|
|
70
|
+
message: Optional acknowledgment message
|
|
71
|
+
processing_time_ms: Processing time in milliseconds
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Strictly typed AckMessage
|
|
75
|
+
"""
|
|
76
|
+
ack_data = AckData(
|
|
77
|
+
acknowledged=True,
|
|
78
|
+
message=message,
|
|
79
|
+
processing_time_ms=processing_time_ms
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return AckMessage(
|
|
83
|
+
correlation_id=correlation_id,
|
|
84
|
+
data=ack_data
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def create_validation_error_message(
|
|
89
|
+
validation_errors: List[str],
|
|
90
|
+
correlation_id: Optional[str] = None
|
|
91
|
+
) -> ErrorMessage:
|
|
92
|
+
"""
|
|
93
|
+
Create a validation error message.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
validation_errors: List of validation error messages
|
|
97
|
+
correlation_id: ID of the message this is responding to
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Strictly typed ErrorMessage for validation errors
|
|
101
|
+
"""
|
|
102
|
+
return create_error_message(
|
|
103
|
+
error_code="VALIDATION_ERROR",
|
|
104
|
+
error_message="Message validation failed",
|
|
105
|
+
correlation_id=correlation_id,
|
|
106
|
+
field_errors=validation_errors
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def create_timeout_error_message(
|
|
111
|
+
operation: str,
|
|
112
|
+
timeout_seconds: float,
|
|
113
|
+
correlation_id: Optional[str] = None
|
|
114
|
+
) -> ErrorMessage:
|
|
115
|
+
"""
|
|
116
|
+
Create a timeout error message.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
operation: Operation that timed out
|
|
120
|
+
timeout_seconds: Timeout duration
|
|
121
|
+
correlation_id: ID of the message this is responding to
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Strictly typed ErrorMessage for timeout errors
|
|
125
|
+
"""
|
|
126
|
+
return create_error_message(
|
|
127
|
+
error_code="TIMEOUT_ERROR",
|
|
128
|
+
error_message=f"Operation '{operation}' timed out after {timeout_seconds} seconds",
|
|
129
|
+
correlation_id=correlation_id,
|
|
130
|
+
retry_after=int(timeout_seconds * 2) # Suggest retry after double the timeout
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def create_connection_error_message(
|
|
135
|
+
reason: str,
|
|
136
|
+
correlation_id: Optional[str] = None
|
|
137
|
+
) -> ErrorMessage:
|
|
138
|
+
"""
|
|
139
|
+
Create a connection error message.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
reason: Connection error reason
|
|
143
|
+
correlation_id: ID of the message this is responding to
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Strictly typed ErrorMessage for connection errors
|
|
147
|
+
"""
|
|
148
|
+
return create_error_message(
|
|
149
|
+
error_code="CONNECTION_ERROR",
|
|
150
|
+
error_message=f"Connection error: {reason}",
|
|
151
|
+
correlation_id=correlation_id,
|
|
152
|
+
retry_after=30 # Suggest retry after 30 seconds
|
|
153
|
+
)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WebSocket Session Models
|
|
3
|
+
|
|
4
|
+
Strictly typed models for WebSocket session management.
|
|
5
|
+
Following critical requirements - no raw Dict[str, Any].
|
|
6
|
+
|
|
7
|
+
Phase 2: Core Systems - WebSocket Session
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import Optional, List
|
|
12
|
+
from pydantic import BaseModel, Field, ConfigDict
|
|
13
|
+
|
|
14
|
+
from .base import UnrealOnBaseModel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DriverSession(UnrealOnBaseModel):
|
|
18
|
+
"""Driver WebSocket session information."""
|
|
19
|
+
|
|
20
|
+
model_config = ConfigDict(
|
|
21
|
+
validate_assignment=True,
|
|
22
|
+
extra="forbid"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
driver_id: str = Field(description="Driver ID")
|
|
26
|
+
driver_type: str = Field(description="Driver type")
|
|
27
|
+
connection_id: str = Field(description="WebSocket connection ID")
|
|
28
|
+
connected_at: datetime = Field(description="Connection timestamp")
|
|
29
|
+
last_seen: datetime = Field(description="Last activity timestamp")
|
|
30
|
+
capabilities: List[str] = Field(description="Driver capabilities")
|
|
31
|
+
status: str = Field(default="connected", description="Connection status")
|
|
32
|
+
active_tasks: int = Field(default=0, description="Number of active tasks")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ConnectionStats(UnrealOnBaseModel):
|
|
36
|
+
"""WebSocket connection statistics."""
|
|
37
|
+
|
|
38
|
+
model_config = ConfigDict(
|
|
39
|
+
validate_assignment=True,
|
|
40
|
+
extra="forbid"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
total_connections: int = Field(description="Total connections made")
|
|
44
|
+
active_connections: int = Field(description="Currently active connections")
|
|
45
|
+
messages_sent: int = Field(description="Total messages sent")
|
|
46
|
+
messages_received: int = Field(description="Total messages received")
|
|
47
|
+
errors: int = Field(description="Number of errors")
|
|
48
|
+
uptime_seconds: float = Field(description="Server uptime in seconds")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BridgeStats(UnrealOnBaseModel):
|
|
52
|
+
"""WebSocket bridge statistics."""
|
|
53
|
+
|
|
54
|
+
model_config = ConfigDict(
|
|
55
|
+
validate_assignment=True,
|
|
56
|
+
extra="forbid"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
active_connections: int = Field(description="Active WebSocket connections")
|
|
60
|
+
total_messages: int = Field(description="Total messages processed")
|
|
61
|
+
arq_jobs_sent: int = Field(description="ARQ jobs sent")
|
|
62
|
+
arq_jobs_failed: int = Field(description="ARQ jobs failed")
|
|
63
|
+
registered_drivers: int = Field(description="Number of registered drivers")
|
|
64
|
+
uptime_seconds: float = Field(description="Bridge uptime in seconds")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ConfigurationData(UnrealOnBaseModel):
|
|
68
|
+
"""Configuration data for drivers."""
|
|
69
|
+
|
|
70
|
+
model_config = ConfigDict(
|
|
71
|
+
validate_assignment=True,
|
|
72
|
+
extra="forbid"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
log_level: Optional[str] = Field(default=None, description="Logging level")
|
|
76
|
+
batch_size: Optional[int] = Field(default=None, description="Batch size for operations")
|
|
77
|
+
timeout_seconds: Optional[float] = Field(default=None, description="Operation timeout")
|
|
78
|
+
proxy_enabled: Optional[bool] = Field(default=None, description="Whether proxy is enabled")
|
|
79
|
+
max_retries: Optional[int] = Field(default=None, description="Maximum retry attempts")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ComponentDetails(UnrealOnBaseModel):
|
|
83
|
+
"""Component details for dashboard."""
|
|
84
|
+
|
|
85
|
+
model_config = ConfigDict(
|
|
86
|
+
validate_assignment=True,
|
|
87
|
+
extra="forbid"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
name: str = Field(description="Component name")
|
|
91
|
+
timestamp: str = Field(description="Timestamp ISO string")
|
|
92
|
+
health: Optional["ComponentHealth"] = Field(default=None, description="Health information")
|
|
93
|
+
metrics: "ComponentMetrics" = Field(description="Component metrics")
|
|
94
|
+
alerts: List["ComponentAlert"] = Field(description="Component alerts")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ComponentHealth(UnrealOnBaseModel):
|
|
98
|
+
"""Component health information."""
|
|
99
|
+
|
|
100
|
+
model_config = ConfigDict(
|
|
101
|
+
validate_assignment=True,
|
|
102
|
+
extra="forbid"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
status: str = Field(description="Health status")
|
|
106
|
+
last_check: str = Field(description="Last check timestamp")
|
|
107
|
+
uptime_seconds: float = Field(description="Uptime in seconds")
|
|
108
|
+
failure_rate: float = Field(description="Failure rate percentage")
|
|
109
|
+
check_count: int = Field(description="Total health checks")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class ComponentMetrics(UnrealOnBaseModel):
|
|
113
|
+
"""Component metrics information."""
|
|
114
|
+
|
|
115
|
+
model_config = ConfigDict(
|
|
116
|
+
validate_assignment=True,
|
|
117
|
+
extra="forbid"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
metric_name: str = Field(description="Metric name")
|
|
121
|
+
metric_type: str = Field(description="Metric type")
|
|
122
|
+
current_value: float = Field(description="Current value")
|
|
123
|
+
total_samples: int = Field(description="Total samples")
|
|
124
|
+
last_updated: str = Field(description="Last updated timestamp")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class ComponentAlert(UnrealOnBaseModel):
|
|
128
|
+
"""Component alert information."""
|
|
129
|
+
|
|
130
|
+
model_config = ConfigDict(
|
|
131
|
+
validate_assignment=True,
|
|
132
|
+
extra="forbid"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
alert_id: str = Field(description="Alert ID")
|
|
136
|
+
rule_name: str = Field(description="Alert rule name")
|
|
137
|
+
severity: str = Field(description="Alert severity")
|
|
138
|
+
message: str = Field(description="Alert message")
|
|
139
|
+
timestamp: str = Field(description="Alert timestamp")
|
|
140
|
+
component_name: Optional[str] = Field(default=None, description="Related component")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Update forward references
|
|
144
|
+
ComponentDetails.model_rebuild()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Monitoring Package
|
|
3
|
+
|
|
4
|
+
Basic monitoring and health checks for UnrealOn RPC system.
|
|
5
|
+
Following critical requirements - max 500 lines, 100% Pydantic v2.
|
|
6
|
+
|
|
7
|
+
Phase 2: Core Systems - Monitoring
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .health_check import (
|
|
11
|
+
HealthStatus, HealthCheckResult, ComponentHealth,
|
|
12
|
+
HealthChecker, health_check_decorator
|
|
13
|
+
)
|
|
14
|
+
from .metrics import (
|
|
15
|
+
MetricType, MetricValue, Metric,
|
|
16
|
+
MetricsCollector, counter, gauge, histogram, timer
|
|
17
|
+
)
|
|
18
|
+
from .alerts import (
|
|
19
|
+
AlertSeverity, AlertRule, Alert,
|
|
20
|
+
AlertManager, alert_on_condition
|
|
21
|
+
)
|
|
22
|
+
from .dashboard import (
|
|
23
|
+
DashboardData, SystemStatus,
|
|
24
|
+
MonitoringDashboard, get_system_overview
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
# Health checks
|
|
29
|
+
'HealthStatus', 'HealthCheckResult', 'ComponentHealth',
|
|
30
|
+
'HealthChecker', 'health_check_decorator',
|
|
31
|
+
|
|
32
|
+
# Metrics
|
|
33
|
+
'MetricType', 'MetricValue', 'Metric',
|
|
34
|
+
'MetricsCollector', 'counter', 'gauge', 'histogram', 'timer',
|
|
35
|
+
|
|
36
|
+
# Alerts
|
|
37
|
+
'AlertSeverity', 'AlertRule', 'Alert',
|
|
38
|
+
'AlertManager', 'alert_on_condition',
|
|
39
|
+
|
|
40
|
+
# Dashboard
|
|
41
|
+
'DashboardData', 'SystemStatus',
|
|
42
|
+
'MonitoringDashboard', 'get_system_overview',
|
|
43
|
+
]
|