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,496 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Proxy WebSocket Models.
|
|
3
|
+
|
|
4
|
+
All proxy-related models for WebSocket communication between Driver and RPC.
|
|
5
|
+
Includes core proxy models and WebSocket message wrappers.
|
|
6
|
+
|
|
7
|
+
Phase 3.4: Proxy System - WebSocket Integration
|
|
8
|
+
Following critical requirements: <500 lines, functions <20 lines, Pydantic v2 only
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import Optional, List
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from pydantic import Field, ConfigDict, field_validator
|
|
15
|
+
|
|
16
|
+
from ..base import UnrealOnBaseModel, TimestampedModel, IdentifiedModel
|
|
17
|
+
from .base import WebSocketMessage, MessageType
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Core Proxy Models
|
|
21
|
+
|
|
22
|
+
class ProxyType(str, Enum):
|
|
23
|
+
"""Proxy connection types."""
|
|
24
|
+
HTTP = "http"
|
|
25
|
+
HTTPS = "https"
|
|
26
|
+
SOCKS4 = "socks4"
|
|
27
|
+
SOCKS5 = "socks5"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ProxyHealthStatus(str, Enum):
|
|
31
|
+
"""Proxy health status levels."""
|
|
32
|
+
HEALTHY = "healthy"
|
|
33
|
+
DEGRADED = "degraded"
|
|
34
|
+
UNHEALTHY = "unhealthy"
|
|
35
|
+
UNKNOWN = "unknown"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ProxyCredentials(UnrealOnBaseModel):
|
|
39
|
+
"""Proxy authentication credentials."""
|
|
40
|
+
username: str = Field(..., min_length=1, max_length=100)
|
|
41
|
+
password: str = Field(..., min_length=1, max_length=200)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ProxyInfo(IdentifiedModel):
|
|
45
|
+
"""Core proxy information for WebSocket communication."""
|
|
46
|
+
host: str = Field(..., min_length=1, max_length=255)
|
|
47
|
+
port: int = Field(..., ge=1, le=65535)
|
|
48
|
+
proxy_type: ProxyType = ProxyType.HTTP
|
|
49
|
+
credentials: Optional[ProxyCredentials] = None
|
|
50
|
+
|
|
51
|
+
# Metadata
|
|
52
|
+
country_code: Optional[str] = Field(None, min_length=2, max_length=2)
|
|
53
|
+
city: Optional[str] = Field(None, max_length=100)
|
|
54
|
+
provider: Optional[str] = Field(None, max_length=100)
|
|
55
|
+
|
|
56
|
+
@field_validator('host')
|
|
57
|
+
@classmethod
|
|
58
|
+
def validate_host(cls, v: str) -> str:
|
|
59
|
+
"""Validate host format."""
|
|
60
|
+
if not v or v.isspace():
|
|
61
|
+
raise ValueError("Host cannot be empty")
|
|
62
|
+
return v.strip()
|
|
63
|
+
|
|
64
|
+
@field_validator('country_code')
|
|
65
|
+
@classmethod
|
|
66
|
+
def validate_country_code(cls, v: Optional[str]) -> Optional[str]:
|
|
67
|
+
"""Validate ISO country code format."""
|
|
68
|
+
if v is None:
|
|
69
|
+
return v
|
|
70
|
+
return v.upper() if len(v) == 2 else v
|
|
71
|
+
|
|
72
|
+
def get_url(self) -> str:
|
|
73
|
+
"""Get proxy URL for HTTP requests."""
|
|
74
|
+
if self.credentials:
|
|
75
|
+
return f"{self.proxy_type}://{self.credentials.username}:{self.credentials.password}@{self.host}:{self.port}"
|
|
76
|
+
return f"{self.proxy_type}://{self.host}:{self.port}"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class ProxyAssignment(TimestampedModel):
|
|
80
|
+
"""Proxy assignment for WebSocket communication."""
|
|
81
|
+
assignment_id: str = Field(..., min_length=1)
|
|
82
|
+
task_id: str = Field(..., min_length=1)
|
|
83
|
+
proxy: ProxyInfo
|
|
84
|
+
|
|
85
|
+
# Assignment details
|
|
86
|
+
expires_at: Optional[datetime] = None
|
|
87
|
+
pool_id: str = Field(..., min_length=1)
|
|
88
|
+
max_requests: Optional[int] = Field(None, ge=1)
|
|
89
|
+
current_requests: int = Field(default=0, ge=0)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# WebSocket Data Payloads
|
|
93
|
+
|
|
94
|
+
class ProxyRequestData(UnrealOnBaseModel):
|
|
95
|
+
"""Proxy request data payload - strictly typed."""
|
|
96
|
+
|
|
97
|
+
model_config = ConfigDict(
|
|
98
|
+
validate_assignment=True,
|
|
99
|
+
extra="forbid"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
task_id: str = Field(
|
|
103
|
+
min_length=1,
|
|
104
|
+
max_length=100,
|
|
105
|
+
description="Task identifier requesting proxy"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
task_type: str = Field(
|
|
109
|
+
min_length=1,
|
|
110
|
+
max_length=50,
|
|
111
|
+
description="Type of task needing proxy"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Requirements
|
|
115
|
+
required_country: Optional[str] = Field(
|
|
116
|
+
default=None,
|
|
117
|
+
min_length=2,
|
|
118
|
+
max_length=2,
|
|
119
|
+
description="Required country code (ISO 2-letter)"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
required_proxy_type: Optional[ProxyType] = Field(
|
|
123
|
+
default=None,
|
|
124
|
+
description="Required proxy type"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
pool_preference: Optional[str] = Field(
|
|
128
|
+
default=None,
|
|
129
|
+
max_length=50,
|
|
130
|
+
description="Preferred proxy pool name"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Context
|
|
134
|
+
target_domain: Optional[str] = Field(
|
|
135
|
+
default=None,
|
|
136
|
+
max_length=255,
|
|
137
|
+
description="Target domain for proxy selection"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
priority: int = Field(
|
|
141
|
+
default=5,
|
|
142
|
+
ge=1,
|
|
143
|
+
le=10,
|
|
144
|
+
description="Request priority (1=low, 10=high)"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
exclude_proxy_ids: List[str] = Field(
|
|
148
|
+
default_factory=list,
|
|
149
|
+
description="Proxy IDs to exclude from selection"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class ProxyResponseData(UnrealOnBaseModel):
|
|
154
|
+
"""Proxy response data payload - strictly typed."""
|
|
155
|
+
|
|
156
|
+
model_config = ConfigDict(
|
|
157
|
+
validate_assignment=True,
|
|
158
|
+
extra="forbid"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
success: bool = Field(
|
|
162
|
+
description="Whether proxy assignment was successful"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
assignment: Optional[ProxyAssignment] = Field(
|
|
166
|
+
default=None,
|
|
167
|
+
description="Proxy assignment details (if successful)"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
error_message: Optional[str] = Field(
|
|
171
|
+
default=None,
|
|
172
|
+
max_length=500,
|
|
173
|
+
description="Error message (if failed)"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
error_code: Optional[str] = Field(
|
|
177
|
+
default=None,
|
|
178
|
+
max_length=50,
|
|
179
|
+
description="Error code (if failed)"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
retry_after_seconds: Optional[int] = Field(
|
|
183
|
+
default=None,
|
|
184
|
+
ge=1,
|
|
185
|
+
le=3600,
|
|
186
|
+
description="Seconds to wait before retry (if applicable)"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
available_pools: List[str] = Field(
|
|
190
|
+
default_factory=list,
|
|
191
|
+
description="Available proxy pools for this request"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ProxyHealthReportData(UnrealOnBaseModel):
|
|
196
|
+
"""Proxy health report data payload - strictly typed."""
|
|
197
|
+
|
|
198
|
+
model_config = ConfigDict(
|
|
199
|
+
validate_assignment=True,
|
|
200
|
+
extra="forbid"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
assignment_id: str = Field(
|
|
204
|
+
min_length=1,
|
|
205
|
+
description="Assignment ID for the proxy"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
proxy_id: str = Field(
|
|
209
|
+
min_length=1,
|
|
210
|
+
description="Proxy identifier"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
task_id: str = Field(
|
|
214
|
+
min_length=1,
|
|
215
|
+
description="Task that used the proxy"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Health status
|
|
219
|
+
status: ProxyHealthStatus = Field(
|
|
220
|
+
description="Current proxy health status"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
response_time_ms: Optional[float] = Field(
|
|
224
|
+
default=None,
|
|
225
|
+
ge=0,
|
|
226
|
+
description="Response time in milliseconds"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
success: bool = Field(
|
|
230
|
+
description="Whether the proxy request was successful"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Error details (if failed)
|
|
234
|
+
error_type: Optional[str] = Field(
|
|
235
|
+
default=None,
|
|
236
|
+
max_length=50,
|
|
237
|
+
description="Error type (if failed)"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
error_message: Optional[str] = Field(
|
|
241
|
+
default=None,
|
|
242
|
+
max_length=500,
|
|
243
|
+
description="Error message (if failed)"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
http_status_code: Optional[int] = Field(
|
|
247
|
+
default=None,
|
|
248
|
+
ge=100,
|
|
249
|
+
le=599,
|
|
250
|
+
description="HTTP status code (if applicable)"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
target_url: Optional[str] = Field(
|
|
254
|
+
default=None,
|
|
255
|
+
max_length=1000,
|
|
256
|
+
description="Target URL that was accessed"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class ProxyRotationRequestData(UnrealOnBaseModel):
|
|
261
|
+
"""Proxy rotation request data payload - strictly typed."""
|
|
262
|
+
|
|
263
|
+
model_config = ConfigDict(
|
|
264
|
+
validate_assignment=True,
|
|
265
|
+
extra="forbid"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
current_assignment_id: str = Field(
|
|
269
|
+
min_length=1,
|
|
270
|
+
description="Current proxy assignment ID"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
reason: str = Field(
|
|
274
|
+
min_length=1,
|
|
275
|
+
max_length=200,
|
|
276
|
+
description="Reason for rotation request"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# New requirements
|
|
280
|
+
new_country_preference: Optional[str] = Field(
|
|
281
|
+
default=None,
|
|
282
|
+
min_length=2,
|
|
283
|
+
max_length=2,
|
|
284
|
+
description="New country preference (if any)"
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
exclude_proxy_ids: List[str] = Field(
|
|
288
|
+
default_factory=list,
|
|
289
|
+
description="Proxy IDs to exclude from new selection"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
urgent: bool = Field(
|
|
293
|
+
default=False,
|
|
294
|
+
description="Whether this is an urgent rotation request"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class ProxyReleaseData(UnrealOnBaseModel):
|
|
299
|
+
"""Proxy release data payload - strictly typed."""
|
|
300
|
+
|
|
301
|
+
model_config = ConfigDict(
|
|
302
|
+
validate_assignment=True,
|
|
303
|
+
extra="forbid"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
assignment_id: str = Field(
|
|
307
|
+
min_length=1,
|
|
308
|
+
description="Assignment ID to release"
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
task_id: str = Field(
|
|
312
|
+
min_length=1,
|
|
313
|
+
description="Task that was using the proxy"
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
reason: str = Field(
|
|
317
|
+
default="task_completed",
|
|
318
|
+
max_length=100,
|
|
319
|
+
description="Reason for release"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# Usage statistics
|
|
323
|
+
requests_made: int = Field(
|
|
324
|
+
default=0,
|
|
325
|
+
ge=0,
|
|
326
|
+
description="Number of requests made with this proxy"
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
bytes_transferred: int = Field(
|
|
330
|
+
default=0,
|
|
331
|
+
ge=0,
|
|
332
|
+
description="Total bytes transferred"
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
session_duration_seconds: float = Field(
|
|
336
|
+
default=0.0,
|
|
337
|
+
ge=0,
|
|
338
|
+
description="Total session duration in seconds"
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# WebSocket Messages
|
|
343
|
+
|
|
344
|
+
class ProxyRequestMessage(WebSocketMessage):
|
|
345
|
+
"""Proxy request message (Driver → Server)."""
|
|
346
|
+
|
|
347
|
+
model_config = ConfigDict(
|
|
348
|
+
validate_assignment=True,
|
|
349
|
+
extra="forbid"
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
type: MessageType = Field(
|
|
353
|
+
default=MessageType.PROXY_REQUEST,
|
|
354
|
+
frozen=True
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
data: ProxyRequestData = Field(
|
|
358
|
+
description="Proxy request data"
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class ProxyResponseMessage(WebSocketMessage):
|
|
363
|
+
"""Proxy response message (Server → Driver)."""
|
|
364
|
+
|
|
365
|
+
model_config = ConfigDict(
|
|
366
|
+
validate_assignment=True,
|
|
367
|
+
extra="forbid"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
type: MessageType = Field(
|
|
371
|
+
default=MessageType.PROXY_RESPONSE,
|
|
372
|
+
frozen=True
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
data: ProxyResponseData = Field(
|
|
376
|
+
description="Proxy response data"
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class ProxyHealthReportMessage(WebSocketMessage):
|
|
381
|
+
"""Proxy health report message (Driver → Server)."""
|
|
382
|
+
|
|
383
|
+
model_config = ConfigDict(
|
|
384
|
+
validate_assignment=True,
|
|
385
|
+
extra="forbid"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
type: MessageType = Field(
|
|
389
|
+
default=MessageType.PROXY_HEALTH_REPORT,
|
|
390
|
+
frozen=True
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
data: ProxyHealthReportData = Field(
|
|
394
|
+
description="Proxy health report data"
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
class ProxyRotationRequestMessage(WebSocketMessage):
|
|
399
|
+
"""Proxy rotation request message (Driver → Server)."""
|
|
400
|
+
|
|
401
|
+
model_config = ConfigDict(
|
|
402
|
+
validate_assignment=True,
|
|
403
|
+
extra="forbid"
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
type: MessageType = Field(
|
|
407
|
+
default=MessageType.PROXY_ROTATION_REQUEST,
|
|
408
|
+
frozen=True
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
data: ProxyRotationRequestData = Field(
|
|
412
|
+
description="Proxy rotation request data"
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class ProxyReleaseMessage(WebSocketMessage):
|
|
417
|
+
"""Proxy release message (Driver → Server)."""
|
|
418
|
+
|
|
419
|
+
model_config = ConfigDict(
|
|
420
|
+
validate_assignment=True,
|
|
421
|
+
extra="forbid"
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
type: MessageType = Field(
|
|
425
|
+
default=MessageType.PROXY_RELEASE,
|
|
426
|
+
frozen=True
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
data: ProxyReleaseData = Field(
|
|
430
|
+
description="Proxy release data"
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
# ===== UTILITY MODELS =====
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class ProxyHealthRecord(UnrealOnBaseModel):
|
|
438
|
+
"""Proxy health tracking record."""
|
|
439
|
+
|
|
440
|
+
status: ProxyHealthStatus = Field(
|
|
441
|
+
description="Current health status"
|
|
442
|
+
)
|
|
443
|
+
response_time_ms: Optional[int] = Field(
|
|
444
|
+
default=None,
|
|
445
|
+
ge=0,
|
|
446
|
+
description="Response time in milliseconds"
|
|
447
|
+
)
|
|
448
|
+
success: bool = Field(
|
|
449
|
+
description="Whether last operation was successful"
|
|
450
|
+
)
|
|
451
|
+
last_update: datetime = Field(
|
|
452
|
+
description="Last update timestamp"
|
|
453
|
+
)
|
|
454
|
+
error_type: Optional[str] = Field(
|
|
455
|
+
default=None,
|
|
456
|
+
description="Error type if any"
|
|
457
|
+
)
|
|
458
|
+
error_message: Optional[str] = Field(
|
|
459
|
+
default=None,
|
|
460
|
+
description="Error message if any"
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class ProxyManagerStats(UnrealOnBaseModel):
|
|
465
|
+
"""Proxy distribution manager statistics."""
|
|
466
|
+
|
|
467
|
+
total_requests: int = Field(
|
|
468
|
+
default=0,
|
|
469
|
+
ge=0,
|
|
470
|
+
description="Total proxy requests"
|
|
471
|
+
)
|
|
472
|
+
successful_assignments: int = Field(
|
|
473
|
+
default=0,
|
|
474
|
+
ge=0,
|
|
475
|
+
description="Successful assignments"
|
|
476
|
+
)
|
|
477
|
+
failed_assignments: int = Field(
|
|
478
|
+
default=0,
|
|
479
|
+
ge=0,
|
|
480
|
+
description="Failed assignments"
|
|
481
|
+
)
|
|
482
|
+
health_reports: int = Field(
|
|
483
|
+
default=0,
|
|
484
|
+
ge=0,
|
|
485
|
+
description="Health reports received"
|
|
486
|
+
)
|
|
487
|
+
active_assignments: int = Field(
|
|
488
|
+
default=0,
|
|
489
|
+
ge=0,
|
|
490
|
+
description="Currently active assignments"
|
|
491
|
+
)
|
|
492
|
+
tracked_health_records: int = Field(
|
|
493
|
+
default=0,
|
|
494
|
+
ge=0,
|
|
495
|
+
description="Health records being tracked"
|
|
496
|
+
)
|