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,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
+ )