unrealon 1.0.9__py3-none-any.whl → 1.1.1__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 (302) hide show
  1. unrealon/__init__.py +23 -21
  2. unrealon-1.1.1.dist-info/METADATA +722 -0
  3. unrealon-1.1.1.dist-info/RECORD +82 -0
  4. {unrealon-1.0.9.dist-info → unrealon-1.1.1.dist-info}/WHEEL +1 -1
  5. unrealon-1.1.1.dist-info/entry_points.txt +9 -0
  6. {unrealon-1.0.9.dist-info → unrealon-1.1.1.dist-info/licenses}/LICENSE +1 -1
  7. unrealon_bridge/__init__.py +114 -0
  8. unrealon_bridge/cli.py +316 -0
  9. unrealon_bridge/client/__init__.py +93 -0
  10. unrealon_bridge/client/base.py +78 -0
  11. unrealon_bridge/client/commands.py +89 -0
  12. unrealon_bridge/client/connection.py +90 -0
  13. unrealon_bridge/client/events.py +65 -0
  14. unrealon_bridge/client/health.py +38 -0
  15. unrealon_bridge/client/html_parser.py +146 -0
  16. unrealon_bridge/client/logging.py +139 -0
  17. unrealon_bridge/client/proxy.py +70 -0
  18. unrealon_bridge/client/scheduler.py +450 -0
  19. unrealon_bridge/client/session.py +70 -0
  20. unrealon_bridge/configs/__init__.py +14 -0
  21. unrealon_bridge/configs/bridge_config.py +212 -0
  22. unrealon_bridge/configs/bridge_config.yaml +39 -0
  23. unrealon_bridge/models/__init__.py +138 -0
  24. unrealon_bridge/models/base.py +28 -0
  25. unrealon_bridge/models/command.py +41 -0
  26. unrealon_bridge/models/events.py +40 -0
  27. unrealon_bridge/models/html_parser.py +79 -0
  28. unrealon_bridge/models/logging.py +55 -0
  29. unrealon_bridge/models/parser.py +63 -0
  30. unrealon_bridge/models/proxy.py +41 -0
  31. unrealon_bridge/models/requests.py +95 -0
  32. unrealon_bridge/models/responses.py +88 -0
  33. unrealon_bridge/models/scheduler.py +592 -0
  34. unrealon_bridge/models/session.py +28 -0
  35. unrealon_bridge/server/__init__.py +91 -0
  36. unrealon_bridge/server/base.py +171 -0
  37. unrealon_bridge/server/handlers/__init__.py +23 -0
  38. unrealon_bridge/server/handlers/command.py +110 -0
  39. unrealon_bridge/server/handlers/html_parser.py +139 -0
  40. unrealon_bridge/server/handlers/logging.py +95 -0
  41. unrealon_bridge/server/handlers/parser.py +95 -0
  42. unrealon_bridge/server/handlers/proxy.py +75 -0
  43. unrealon_bridge/server/handlers/scheduler.py +545 -0
  44. unrealon_bridge/server/handlers/session.py +66 -0
  45. unrealon_browser/__init__.py +61 -18
  46. unrealon_browser/{src/cli → cli}/browser_cli.py +6 -13
  47. unrealon_browser/{src/cli → cli}/cookies_cli.py +5 -1
  48. unrealon_browser/{src/core → core}/browser_manager.py +2 -2
  49. unrealon_browser/{src/managers → managers}/captcha.py +1 -1
  50. unrealon_browser/{src/managers → managers}/cookies.py +1 -1
  51. unrealon_browser/managers/logger_bridge.py +231 -0
  52. unrealon_browser/{src/managers → managers}/profile.py +1 -1
  53. unrealon_driver/__init__.py +73 -19
  54. unrealon_driver/browser/__init__.py +8 -0
  55. unrealon_driver/browser/config.py +74 -0
  56. unrealon_driver/browser/manager.py +416 -0
  57. unrealon_driver/exceptions.py +28 -0
  58. unrealon_driver/parser/__init__.py +55 -0
  59. unrealon_driver/parser/cli_manager.py +141 -0
  60. unrealon_driver/parser/daemon_manager.py +227 -0
  61. unrealon_driver/parser/managers/__init__.py +46 -0
  62. unrealon_driver/parser/managers/browser.py +51 -0
  63. unrealon_driver/parser/managers/config.py +281 -0
  64. unrealon_driver/parser/managers/error.py +412 -0
  65. unrealon_driver/parser/managers/html.py +732 -0
  66. unrealon_driver/parser/managers/logging.py +609 -0
  67. unrealon_driver/parser/managers/result.py +321 -0
  68. unrealon_driver/parser/parser_manager.py +628 -0
  69. unrealon/sdk_config.py +0 -88
  70. unrealon-1.0.9.dist-info/METADATA +0 -810
  71. unrealon-1.0.9.dist-info/RECORD +0 -246
  72. unrealon_browser/pyproject.toml +0 -182
  73. unrealon_browser/src/__init__.py +0 -62
  74. unrealon_browser/src/managers/logger_bridge.py +0 -395
  75. unrealon_driver/README.md +0 -204
  76. unrealon_driver/pyproject.toml +0 -187
  77. unrealon_driver/src/__init__.py +0 -90
  78. unrealon_driver/src/cli/__init__.py +0 -10
  79. unrealon_driver/src/cli/main.py +0 -66
  80. unrealon_driver/src/cli/simple.py +0 -510
  81. unrealon_driver/src/config/__init__.py +0 -11
  82. unrealon_driver/src/config/auto_config.py +0 -478
  83. unrealon_driver/src/core/__init__.py +0 -18
  84. unrealon_driver/src/core/exceptions.py +0 -289
  85. unrealon_driver/src/core/parser.py +0 -638
  86. unrealon_driver/src/dto/__init__.py +0 -66
  87. unrealon_driver/src/dto/cli.py +0 -119
  88. unrealon_driver/src/dto/config.py +0 -18
  89. unrealon_driver/src/dto/events.py +0 -237
  90. unrealon_driver/src/dto/execution.py +0 -313
  91. unrealon_driver/src/dto/services.py +0 -311
  92. unrealon_driver/src/execution/__init__.py +0 -23
  93. unrealon_driver/src/execution/daemon_mode.py +0 -317
  94. unrealon_driver/src/execution/interactive_mode.py +0 -88
  95. unrealon_driver/src/execution/modes.py +0 -45
  96. unrealon_driver/src/execution/scheduled_mode.py +0 -209
  97. unrealon_driver/src/execution/test_mode.py +0 -250
  98. unrealon_driver/src/logging/__init__.py +0 -24
  99. unrealon_driver/src/logging/driver_logger.py +0 -512
  100. unrealon_driver/src/services/__init__.py +0 -24
  101. unrealon_driver/src/services/browser_service.py +0 -726
  102. unrealon_driver/src/services/llm/__init__.py +0 -15
  103. unrealon_driver/src/services/llm/browser_llm_service.py +0 -363
  104. unrealon_driver/src/services/llm/llm.py +0 -195
  105. unrealon_driver/src/services/logger_service.py +0 -232
  106. unrealon_driver/src/services/metrics_service.py +0 -185
  107. unrealon_driver/src/services/scheduler_service.py +0 -489
  108. unrealon_driver/src/services/websocket_service.py +0 -362
  109. unrealon_driver/src/utils/__init__.py +0 -16
  110. unrealon_driver/src/utils/service_factory.py +0 -317
  111. unrealon_driver/src/utils/time_formatter.py +0 -338
  112. unrealon_llm/README.md +0 -44
  113. unrealon_llm/__init__.py +0 -26
  114. unrealon_llm/pyproject.toml +0 -154
  115. unrealon_llm/src/__init__.py +0 -228
  116. unrealon_llm/src/cli/__init__.py +0 -0
  117. unrealon_llm/src/core/__init__.py +0 -11
  118. unrealon_llm/src/core/smart_client.py +0 -438
  119. unrealon_llm/src/dto/__init__.py +0 -155
  120. unrealon_llm/src/dto/models/__init__.py +0 -0
  121. unrealon_llm/src/dto/models/config.py +0 -343
  122. unrealon_llm/src/dto/models/core.py +0 -328
  123. unrealon_llm/src/dto/models/enums.py +0 -123
  124. unrealon_llm/src/dto/models/html_analysis.py +0 -345
  125. unrealon_llm/src/dto/models/statistics.py +0 -473
  126. unrealon_llm/src/dto/models/translation.py +0 -383
  127. unrealon_llm/src/dto/models/type_conversion.py +0 -462
  128. unrealon_llm/src/dto/schemas/__init__.py +0 -0
  129. unrealon_llm/src/exceptions.py +0 -392
  130. unrealon_llm/src/llm_config/__init__.py +0 -20
  131. unrealon_llm/src/llm_config/logging_config.py +0 -178
  132. unrealon_llm/src/llm_logging/__init__.py +0 -42
  133. unrealon_llm/src/llm_logging/llm_events.py +0 -107
  134. unrealon_llm/src/llm_logging/llm_logger.py +0 -466
  135. unrealon_llm/src/managers/__init__.py +0 -15
  136. unrealon_llm/src/managers/cache_manager.py +0 -67
  137. unrealon_llm/src/managers/cost_manager.py +0 -107
  138. unrealon_llm/src/managers/request_manager.py +0 -298
  139. unrealon_llm/src/modules/__init__.py +0 -0
  140. unrealon_llm/src/modules/html_processor/__init__.py +0 -25
  141. unrealon_llm/src/modules/html_processor/base_processor.py +0 -415
  142. unrealon_llm/src/modules/html_processor/details_processor.py +0 -85
  143. unrealon_llm/src/modules/html_processor/listing_processor.py +0 -91
  144. unrealon_llm/src/modules/html_processor/models/__init__.py +0 -20
  145. unrealon_llm/src/modules/html_processor/models/processing_models.py +0 -40
  146. unrealon_llm/src/modules/html_processor/models/universal_model.py +0 -56
  147. unrealon_llm/src/modules/html_processor/processor.py +0 -102
  148. unrealon_llm/src/modules/llm/__init__.py +0 -0
  149. unrealon_llm/src/modules/translator/__init__.py +0 -0
  150. unrealon_llm/src/provider.py +0 -116
  151. unrealon_llm/src/utils/__init__.py +0 -95
  152. unrealon_llm/src/utils/common.py +0 -64
  153. unrealon_llm/src/utils/data_extractor.py +0 -188
  154. unrealon_llm/src/utils/html_cleaner.py +0 -767
  155. unrealon_llm/src/utils/language_detector.py +0 -308
  156. unrealon_llm/src/utils/models_cache.py +0 -592
  157. unrealon_llm/src/utils/smart_counter.py +0 -229
  158. unrealon_llm/src/utils/token_counter.py +0 -189
  159. unrealon_sdk/README.md +0 -25
  160. unrealon_sdk/__init__.py +0 -30
  161. unrealon_sdk/pyproject.toml +0 -231
  162. unrealon_sdk/src/__init__.py +0 -150
  163. unrealon_sdk/src/cli/__init__.py +0 -12
  164. unrealon_sdk/src/cli/commands/__init__.py +0 -22
  165. unrealon_sdk/src/cli/commands/benchmark.py +0 -42
  166. unrealon_sdk/src/cli/commands/diagnostics.py +0 -573
  167. unrealon_sdk/src/cli/commands/health.py +0 -46
  168. unrealon_sdk/src/cli/commands/integration.py +0 -498
  169. unrealon_sdk/src/cli/commands/reports.py +0 -43
  170. unrealon_sdk/src/cli/commands/security.py +0 -36
  171. unrealon_sdk/src/cli/commands/server.py +0 -483
  172. unrealon_sdk/src/cli/commands/servers.py +0 -56
  173. unrealon_sdk/src/cli/commands/tests.py +0 -55
  174. unrealon_sdk/src/cli/main.py +0 -126
  175. unrealon_sdk/src/cli/utils/reporter.py +0 -519
  176. unrealon_sdk/src/clients/openapi.yaml +0 -3347
  177. unrealon_sdk/src/clients/python_http/__init__.py +0 -3
  178. unrealon_sdk/src/clients/python_http/api_config.py +0 -228
  179. unrealon_sdk/src/clients/python_http/models/BaseModel.py +0 -12
  180. unrealon_sdk/src/clients/python_http/models/BroadcastDeliveryStats.py +0 -33
  181. unrealon_sdk/src/clients/python_http/models/BroadcastMessage.py +0 -17
  182. unrealon_sdk/src/clients/python_http/models/BroadcastMessageRequest.py +0 -35
  183. unrealon_sdk/src/clients/python_http/models/BroadcastPriority.py +0 -10
  184. unrealon_sdk/src/clients/python_http/models/BroadcastResponse.py +0 -21
  185. unrealon_sdk/src/clients/python_http/models/BroadcastResultResponse.py +0 -33
  186. unrealon_sdk/src/clients/python_http/models/BroadcastTarget.py +0 -11
  187. unrealon_sdk/src/clients/python_http/models/ConnectionStats.py +0 -27
  188. unrealon_sdk/src/clients/python_http/models/ConnectionsResponse.py +0 -21
  189. unrealon_sdk/src/clients/python_http/models/DeveloperMessageResponse.py +0 -23
  190. unrealon_sdk/src/clients/python_http/models/ErrorResponse.py +0 -25
  191. unrealon_sdk/src/clients/python_http/models/HTTPValidationError.py +0 -16
  192. unrealon_sdk/src/clients/python_http/models/HealthResponse.py +0 -23
  193. unrealon_sdk/src/clients/python_http/models/HealthStatus.py +0 -33
  194. unrealon_sdk/src/clients/python_http/models/LogLevel.py +0 -10
  195. unrealon_sdk/src/clients/python_http/models/LoggingRequest.py +0 -27
  196. unrealon_sdk/src/clients/python_http/models/LoggingResponse.py +0 -23
  197. unrealon_sdk/src/clients/python_http/models/MaintenanceMode.py +0 -9
  198. unrealon_sdk/src/clients/python_http/models/MaintenanceModeRequest.py +0 -33
  199. unrealon_sdk/src/clients/python_http/models/MaintenanceStatusResponse.py +0 -39
  200. unrealon_sdk/src/clients/python_http/models/ParserCommandRequest.py +0 -25
  201. unrealon_sdk/src/clients/python_http/models/ParserMessageResponse.py +0 -21
  202. unrealon_sdk/src/clients/python_http/models/ParserRegistrationRequest.py +0 -28
  203. unrealon_sdk/src/clients/python_http/models/ParserRegistrationResponse.py +0 -25
  204. unrealon_sdk/src/clients/python_http/models/ParserType.py +0 -10
  205. unrealon_sdk/src/clients/python_http/models/ProxyBlockRequest.py +0 -19
  206. unrealon_sdk/src/clients/python_http/models/ProxyEndpointResponse.py +0 -20
  207. unrealon_sdk/src/clients/python_http/models/ProxyListResponse.py +0 -19
  208. unrealon_sdk/src/clients/python_http/models/ProxyProvider.py +0 -10
  209. unrealon_sdk/src/clients/python_http/models/ProxyPurchaseRequest.py +0 -25
  210. unrealon_sdk/src/clients/python_http/models/ProxyResponse.py +0 -47
  211. unrealon_sdk/src/clients/python_http/models/ProxyRotationRequest.py +0 -23
  212. unrealon_sdk/src/clients/python_http/models/ProxyStatus.py +0 -10
  213. unrealon_sdk/src/clients/python_http/models/ProxyUsageRequest.py +0 -19
  214. unrealon_sdk/src/clients/python_http/models/ProxyUsageStatsResponse.py +0 -26
  215. unrealon_sdk/src/clients/python_http/models/ServiceRegistrationDto.py +0 -23
  216. unrealon_sdk/src/clients/python_http/models/ServiceStatsResponse.py +0 -31
  217. unrealon_sdk/src/clients/python_http/models/SessionStartRequest.py +0 -23
  218. unrealon_sdk/src/clients/python_http/models/SuccessResponse.py +0 -25
  219. unrealon_sdk/src/clients/python_http/models/SystemNotificationResponse.py +0 -23
  220. unrealon_sdk/src/clients/python_http/models/ValidationError.py +0 -18
  221. unrealon_sdk/src/clients/python_http/models/ValidationErrorResponse.py +0 -21
  222. unrealon_sdk/src/clients/python_http/models/WebSocketMetrics.py +0 -21
  223. unrealon_sdk/src/clients/python_http/models/__init__.py +0 -44
  224. unrealon_sdk/src/clients/python_http/services/None_service.py +0 -35
  225. unrealon_sdk/src/clients/python_http/services/ParserManagement_service.py +0 -190
  226. unrealon_sdk/src/clients/python_http/services/ProxyManagement_service.py +0 -289
  227. unrealon_sdk/src/clients/python_http/services/SocketLogging_service.py +0 -187
  228. unrealon_sdk/src/clients/python_http/services/SystemHealth_service.py +0 -119
  229. unrealon_sdk/src/clients/python_http/services/WebSocketAPI_service.py +0 -198
  230. unrealon_sdk/src/clients/python_http/services/__init__.py +0 -0
  231. unrealon_sdk/src/clients/python_http/services/admin_service.py +0 -125
  232. unrealon_sdk/src/clients/python_http/services/async_None_service.py +0 -35
  233. unrealon_sdk/src/clients/python_http/services/async_ParserManagement_service.py +0 -190
  234. unrealon_sdk/src/clients/python_http/services/async_ProxyManagement_service.py +0 -289
  235. unrealon_sdk/src/clients/python_http/services/async_SocketLogging_service.py +0 -189
  236. unrealon_sdk/src/clients/python_http/services/async_SystemHealth_service.py +0 -123
  237. unrealon_sdk/src/clients/python_http/services/async_WebSocketAPI_service.py +0 -200
  238. unrealon_sdk/src/clients/python_http/services/async_admin_service.py +0 -125
  239. unrealon_sdk/src/clients/python_websocket/__init__.py +0 -28
  240. unrealon_sdk/src/clients/python_websocket/client.py +0 -490
  241. unrealon_sdk/src/clients/python_websocket/events.py +0 -732
  242. unrealon_sdk/src/clients/python_websocket/example.py +0 -136
  243. unrealon_sdk/src/clients/python_websocket/types.py +0 -871
  244. unrealon_sdk/src/core/__init__.py +0 -64
  245. unrealon_sdk/src/core/client.py +0 -556
  246. unrealon_sdk/src/core/config.py +0 -465
  247. unrealon_sdk/src/core/exceptions.py +0 -239
  248. unrealon_sdk/src/core/metadata.py +0 -191
  249. unrealon_sdk/src/core/models.py +0 -142
  250. unrealon_sdk/src/core/types.py +0 -68
  251. unrealon_sdk/src/dto/__init__.py +0 -268
  252. unrealon_sdk/src/dto/authentication.py +0 -108
  253. unrealon_sdk/src/dto/cache.py +0 -208
  254. unrealon_sdk/src/dto/common.py +0 -19
  255. unrealon_sdk/src/dto/concurrency.py +0 -393
  256. unrealon_sdk/src/dto/events.py +0 -108
  257. unrealon_sdk/src/dto/health.py +0 -339
  258. unrealon_sdk/src/dto/load_balancing.py +0 -336
  259. unrealon_sdk/src/dto/logging.py +0 -230
  260. unrealon_sdk/src/dto/performance.py +0 -165
  261. unrealon_sdk/src/dto/rate_limiting.py +0 -295
  262. unrealon_sdk/src/dto/resource_pooling.py +0 -128
  263. unrealon_sdk/src/dto/structured_logging.py +0 -112
  264. unrealon_sdk/src/dto/task_scheduling.py +0 -121
  265. unrealon_sdk/src/dto/websocket.py +0 -55
  266. unrealon_sdk/src/enterprise/__init__.py +0 -59
  267. unrealon_sdk/src/enterprise/authentication.py +0 -401
  268. unrealon_sdk/src/enterprise/cache_manager.py +0 -578
  269. unrealon_sdk/src/enterprise/error_recovery.py +0 -494
  270. unrealon_sdk/src/enterprise/event_system.py +0 -549
  271. unrealon_sdk/src/enterprise/health_monitor.py +0 -747
  272. unrealon_sdk/src/enterprise/load_balancer.py +0 -964
  273. unrealon_sdk/src/enterprise/logging/__init__.py +0 -68
  274. unrealon_sdk/src/enterprise/logging/cleanup.py +0 -156
  275. unrealon_sdk/src/enterprise/logging/development.py +0 -744
  276. unrealon_sdk/src/enterprise/logging/service.py +0 -410
  277. unrealon_sdk/src/enterprise/multithreading_manager.py +0 -853
  278. unrealon_sdk/src/enterprise/performance_monitor.py +0 -539
  279. unrealon_sdk/src/enterprise/proxy_manager.py +0 -696
  280. unrealon_sdk/src/enterprise/rate_limiter.py +0 -652
  281. unrealon_sdk/src/enterprise/resource_pool.py +0 -763
  282. unrealon_sdk/src/enterprise/task_scheduler.py +0 -709
  283. unrealon_sdk/src/internal/__init__.py +0 -10
  284. unrealon_sdk/src/internal/command_router.py +0 -497
  285. unrealon_sdk/src/internal/connection_manager.py +0 -397
  286. unrealon_sdk/src/internal/http_client.py +0 -446
  287. unrealon_sdk/src/internal/websocket_client.py +0 -420
  288. unrealon_sdk/src/provider.py +0 -471
  289. unrealon_sdk/src/utils.py +0 -234
  290. /unrealon_browser/{src/cli → cli}/__init__.py +0 -0
  291. /unrealon_browser/{src/cli → cli}/interactive_mode.py +0 -0
  292. /unrealon_browser/{src/cli → cli}/main.py +0 -0
  293. /unrealon_browser/{src/core → core}/__init__.py +0 -0
  294. /unrealon_browser/{src/dto → dto}/__init__.py +0 -0
  295. /unrealon_browser/{src/dto → dto}/models/config.py +0 -0
  296. /unrealon_browser/{src/dto → dto}/models/core.py +0 -0
  297. /unrealon_browser/{src/dto → dto}/models/dataclasses.py +0 -0
  298. /unrealon_browser/{src/dto → dto}/models/detection.py +0 -0
  299. /unrealon_browser/{src/dto → dto}/models/enums.py +0 -0
  300. /unrealon_browser/{src/dto → dto}/models/statistics.py +0 -0
  301. /unrealon_browser/{src/managers → managers}/__init__.py +0 -0
  302. /unrealon_browser/{src/managers → managers}/stealth.py +0 -0
@@ -1,696 +0,0 @@
1
- """
2
- ProxyManager - Intelligent Proxy Management for Enterprise Parsing
3
-
4
- Layer 3: Infrastructure Services - Core proxy management with:
5
- - Geographic rotation and health checking
6
- - Automatic failover and recovery
7
- - Integration with multiple proxy providers
8
- - Performance monitoring and optimization
9
- - Type-safe operations with Pydantic v2
10
-
11
- Enterprise Features:
12
- - Smart proxy rotation based on success rates
13
- - Geographic targeting for region-specific parsing
14
- - Health monitoring with automatic blacklisting
15
- - Provider failover and load balancing
16
- - Real-time proxy performance metrics
17
- """
18
-
19
- import asyncio
20
- import logging
21
- from datetime import datetime, timedelta, timezone
22
- from typing import Dict, List, Optional, Set, Any
23
- from dataclasses import dataclass, field
24
- from enum import Enum
25
- import random
26
-
27
- # Pydantic v2 for all data models
28
- from pydantic import BaseModel, Field, ConfigDict
29
-
30
- # Auto-generated models from the API - HTTP models
31
- from unrealon_sdk.src.clients.python_http.models import (
32
- ProxyListResponse,
33
- ProxyUsageStatsResponse,
34
- ProxyRotationRequest,
35
- ProxyPurchaseRequest,
36
- ProxyBlockRequest,
37
- ProxyEndpointResponse,
38
- ProxyResponse,
39
- ErrorResponse,
40
- )
41
-
42
- # Auto-generated models from WebSocket types
43
- from unrealon_sdk.src.clients.python_websocket.types import (
44
- ProxyProvider,
45
- ProxyStatus,
46
- ProxyProtocol,
47
- ProxyRotationStrategy,
48
- Proxy,
49
- ProxyEndpoint,
50
- ProxyCredentials,
51
- ProxyUsageStats,
52
- ProxyAllocation,
53
- ProxySummary,
54
- ProxyDetails,
55
- ProxyStatistics,
56
- )
57
-
58
- # Import auto-generated proxy management services
59
- from unrealon_sdk.src.clients.python_http.services.async_ProxyManagement_service import (
60
- list_proxies_api_v1_proxies__get,
61
- get_proxy_statistics_api_v1_proxies_statistics_get,
62
- record_proxy_usage_api_v1_proxies__proxy_id__usage_post,
63
- report_blocked_proxy_api_v1_proxies_rotation_block_post,
64
- request_proxy_rotation_api_v1_proxies_rotation_request_post,
65
- )
66
-
67
- # Core SDK components
68
- from unrealon_sdk.src.core.config import AdapterConfig, ProxyConfig
69
- from unrealon_sdk.src.core.exceptions import ProxyError, ConnectionError
70
- from unrealon_sdk.src.utils import generate_correlation_id
71
-
72
- # Development logging
73
- from .logging.development import (
74
- get_development_logger,
75
- SDKEventType,
76
- SDKContext,
77
- track_development_operation,
78
- )
79
-
80
- logger = logging.getLogger(__name__)
81
-
82
-
83
- # Use auto-generated ProxyUsageStats but extend with helper methods
84
- class ExtendedProxyUsageStats(ProxyUsageStats):
85
- """Extended proxy usage stats with helper methods."""
86
-
87
- @property
88
- def success_rate_percentage(self) -> float:
89
- """Calculate success rate as percentage."""
90
- if self.total_requests == 0:
91
- return 0.0
92
- return (self.successful_requests / self.total_requests) * 100
93
-
94
- @property
95
- def is_healthy(self) -> bool:
96
- """Check if proxy usage indicates healthy status."""
97
- return self.consecutive_failures < 3 and self.success_rate >= 70.0
98
-
99
-
100
- # Extended proxy model with management features
101
- class ManagedProxy(Proxy):
102
- """Extended Proxy model with management features."""
103
-
104
- # Management fields
105
- is_active: bool = Field(default=True, description="Whether proxy is currently active")
106
- last_health_check: Optional[datetime] = Field(
107
- default=None, description="Last health check timestamp"
108
- )
109
- blacklisted_until: Optional[datetime] = Field(
110
- default=None, description="Blacklist expiration time"
111
- )
112
-
113
- @property
114
- def proxy_url(self) -> str:
115
- """Generate proxy URL for HTTP clients."""
116
- if self.credentials:
117
- auth = f"{self.credentials.username}:{self.credentials.password}@"
118
- else:
119
- auth = ""
120
- protocol = (
121
- self.endpoint.protocol.value
122
- if hasattr(self.endpoint.protocol, "value")
123
- else str(self.endpoint.protocol)
124
- )
125
- return f"{protocol}://{auth}{self.endpoint.host}:{self.endpoint.port}"
126
-
127
- @property
128
- def identifier(self) -> str:
129
- """Unique identifier for this proxy."""
130
- return f"{self.endpoint.host}:{self.endpoint.port}"
131
-
132
- @property
133
- def is_blacklisted(self) -> bool:
134
- """Check if proxy is currently blacklisted."""
135
- if self.blacklisted_until is None:
136
- return False
137
- return datetime.now(timezone.utc) < self.blacklisted_until
138
-
139
-
140
- class ProxyPool:
141
- """Manages a pool of proxy endpoints with intelligent selection using auto-generated models."""
142
-
143
- def __init__(self, strategy: ProxyRotationStrategy = ProxyRotationStrategy.SUCCESS_RATE):
144
- self.proxies: Dict[str, ManagedProxy] = {}
145
- self.strategy = strategy
146
- self._rotation_index = 0
147
-
148
- def add_proxy(self, proxy: ManagedProxy) -> None:
149
- """Add a proxy to the pool."""
150
- self.proxies[proxy.identifier] = proxy
151
- logger.debug(f"Added proxy {proxy.identifier} to pool")
152
-
153
- def remove_proxy(self, proxy_id: str) -> None:
154
- """Remove a proxy from the pool."""
155
- if proxy_id in self.proxies:
156
- del self.proxies[proxy_id]
157
- logger.debug(f"Removed proxy {proxy_id} from pool")
158
-
159
- def blacklist_proxy(self, proxy_id: str, duration_minutes: int = 30) -> None:
160
- """Temporarily blacklist a proxy."""
161
- if proxy_id in self.proxies:
162
- blacklist_until = datetime.now(timezone.utc) + timedelta(minutes=duration_minutes)
163
- self.proxies[proxy_id].blacklisted_until = blacklist_until
164
- self.proxies[proxy_id].is_active = False
165
-
166
- logger.warning(f"Blacklisted proxy {proxy_id} for {duration_minutes} minutes")
167
-
168
- # Schedule automatic removal from blacklist
169
- asyncio.create_task(self._remove_from_blacklist_later(proxy_id, duration_minutes))
170
-
171
- async def _remove_from_blacklist_later(self, proxy_id: str, minutes: int) -> None:
172
- """Remove proxy from blacklist after specified time."""
173
- await asyncio.sleep(minutes * 60)
174
- if proxy_id in self.proxies:
175
- self.proxies[proxy_id].blacklisted_until = None
176
- self.proxies[proxy_id].is_active = True
177
- logger.info(f"Proxy {proxy_id} removed from blacklist")
178
-
179
- def get_available_proxies(self) -> List[ManagedProxy]:
180
- """Get list of available (non-blacklisted, healthy) proxies."""
181
- return [
182
- proxy
183
- for proxy in self.proxies.values()
184
- if proxy.is_active and not proxy.is_blacklisted and proxy.usage_stats.is_healthy
185
- ]
186
-
187
- def select_proxy(self, region: Optional[str] = None) -> Optional[ManagedProxy]:
188
- """Select best proxy based on strategy."""
189
- available = self.get_available_proxies()
190
-
191
- if not available:
192
- logger.warning("No available proxies in pool")
193
- return None
194
-
195
- # Filter by region if specified
196
- if region:
197
- regional = [p for p in available if p.region == region or p.country == region]
198
- if regional:
199
- available = regional
200
-
201
- if self.strategy == ProxyRotationStrategy.ROUND_ROBIN:
202
- return self._select_round_robin(available)
203
- elif self.strategy == ProxyRotationStrategy.SUCCESS_RATE:
204
- return self._select_by_success_rate(available)
205
- elif self.strategy == ProxyRotationStrategy.WEIGHTED_RANDOM:
206
- return self._select_weighted_random(available)
207
- elif self.strategy == ProxyRotationStrategy.LEAST_FAILURES:
208
- return self._select_least_failures(available)
209
- elif self.strategy == ProxyRotationStrategy.LEAST_USED:
210
- return self._select_least_used(available)
211
- else:
212
- return available[0] # Fallback
213
-
214
- def _select_round_robin(self, available: List[ManagedProxy]) -> ManagedProxy:
215
- """Round-robin selection."""
216
- proxy = available[self._rotation_index % len(available)]
217
- self._rotation_index += 1
218
- return proxy
219
-
220
- def _select_by_success_rate(self, available: List[ManagedProxy]) -> ManagedProxy:
221
- """Select proxy with highest success rate."""
222
- return max(available, key=lambda p: p.usage_stats.success_rate)
223
-
224
- def _select_weighted_random(self, available: List[ManagedProxy]) -> ManagedProxy:
225
- """Weighted random selection based on success rate."""
226
- weights = [max(p.usage_stats.success_rate, 0.1) for p in available]
227
- return random.choices(available, weights=weights)[0]
228
-
229
- def _select_least_failures(self, available: List[ManagedProxy]) -> ManagedProxy:
230
- """Select proxy with least consecutive failures."""
231
- return min(available, key=lambda p: p.usage_stats.consecutive_failures)
232
-
233
- def _select_least_used(self, available: List[ManagedProxy]) -> ManagedProxy:
234
- """Select proxy used least recently."""
235
-
236
- def last_used_timestamp(proxy: ManagedProxy) -> float:
237
- if proxy.usage_stats.last_used_at:
238
- # Convert string timestamp to comparable format
239
- try:
240
- dt = datetime.fromisoformat(
241
- proxy.usage_stats.last_used_at.replace("Z", "+00:00")
242
- )
243
- return dt.timestamp()
244
- except:
245
- return 0.0
246
- return 0.0
247
-
248
- return min(available, key=last_used_timestamp)
249
-
250
-
251
- class ProxyManager:
252
- """
253
- Enterprise-grade proxy management with intelligent rotation and health monitoring.
254
-
255
- Features:
256
- - Multiple proxy provider integration
257
- - Smart rotation strategies
258
- - Health monitoring and automatic failover
259
- - Performance metrics and optimization
260
- - Geographic targeting
261
- """
262
-
263
- def __init__(self, config: AdapterConfig):
264
- """
265
- Initialize ProxyManager with configuration.
266
-
267
- Args:
268
- config: Adapter configuration containing proxy settings
269
- """
270
- self.config = config
271
- self.proxy_config = config.proxy_config
272
- self.logger = logger
273
-
274
- # Development logging
275
- self.dev_logger = get_development_logger()
276
- if self.dev_logger:
277
- self.dev_logger.set_component_context("ProxyManager")
278
- self.dev_logger.log_info(
279
- SDKEventType.PROXY_MANAGER_INITIALIZED,
280
- f"ProxyManager initialization started with strategy: {self.proxy_config.rotation_strategy}",
281
- context=SDKContext(
282
- component_name="ProxyManager",
283
- metadata={
284
- "rotation_strategy": self.proxy_config.rotation_strategy,
285
- "enabled": self.proxy_config.enabled,
286
- "max_retries": self.proxy_config.max_retries,
287
- },
288
- ),
289
- )
290
-
291
- # Initialize proxy pool with configured strategy
292
- strategy = ProxyRotationStrategy(self.proxy_config.rotation_strategy)
293
- self.pool = ProxyPool(strategy)
294
-
295
- # Health monitoring
296
- self._health_check_interval = 300 # 5 minutes
297
- self._health_check_task: Optional[asyncio.Task] = None
298
-
299
- # Statistics
300
- self._total_requests = 0
301
- self._successful_requests = 0
302
- self._failed_requests = 0
303
-
304
- # HTTP client for proxy API calls (will be injected)
305
- self._http_client = None
306
-
307
- self.logger.info(f"ProxyManager initialized with strategy: {strategy.value}")
308
-
309
- if self.dev_logger:
310
- self.dev_logger.log_info(
311
- SDKEventType.COMPONENT_CREATED,
312
- "ProxyManager initialization completed successfully",
313
- success=True,
314
- context=SDKContext(component_name="ProxyManager"),
315
- )
316
-
317
- async def initialize(self, http_client) -> None:
318
- """Initialize proxy manager with HTTP client."""
319
- self._http_client = http_client
320
-
321
- if self.proxy_config.enabled:
322
- await self._load_initial_proxies()
323
- await self._start_health_monitoring()
324
-
325
- self.logger.info("ProxyManager initialization complete")
326
-
327
- async def shutdown(self) -> None:
328
- """Shutdown proxy manager and cleanup resources."""
329
- if self._health_check_task:
330
- self._health_check_task.cancel()
331
- try:
332
- await self._health_check_task
333
- except asyncio.CancelledError:
334
- pass
335
-
336
- self.logger.info("ProxyManager shutdown complete")
337
-
338
- async def _load_initial_proxies(self) -> None:
339
- """Load initial proxy list from configured providers using real API."""
340
- try:
341
- if not self._http_client:
342
- raise ProxyError("HTTP client not initialized")
343
-
344
- self.logger.info("Loading initial proxy list from providers via API...")
345
-
346
- # Call the real proxy list API
347
- proxy_list_response = await list_proxies_api_v1_proxies__get(
348
- healthy_only=True, limit=100, api_config_override=self._http_client._api_config
349
- )
350
-
351
- if not proxy_list_response or not proxy_list_response.items:
352
- self.logger.warning("No proxies returned from API")
353
- return
354
-
355
- # Convert API response to ManagedProxy objects
356
- for proxy_response in proxy_list_response.items:
357
- managed_proxy = self._convert_api_proxy_to_managed(proxy_response)
358
- self.pool.add_proxy(managed_proxy)
359
-
360
- self.logger.info(f"Loaded {len(proxy_list_response.items)} proxies into pool")
361
-
362
- except Exception as e:
363
- self.logger.error(f"Failed to load initial proxies: {e}")
364
- raise ProxyError(f"Failed to initialize proxy pool: {e}")
365
-
366
- def _convert_api_proxy_to_managed(self, proxy_response: ProxyResponse) -> ManagedProxy:
367
- """Convert API ProxyResponse to ManagedProxy."""
368
- return ManagedProxy(
369
- proxy_id=proxy_response.proxy_id,
370
- provider=proxy_response.provider,
371
- provider_proxy_id=proxy_response.provider_proxy_id,
372
- endpoint=ProxyEndpoint(
373
- host=proxy_response.endpoint.host,
374
- port=proxy_response.endpoint.port,
375
- protocol=ProxyProtocol(proxy_response.endpoint.protocol),
376
- ),
377
- credentials=(
378
- ProxyCredentials(username="", password="") # Will be populated from provider config
379
- if proxy_response.endpoint.connection_string
380
- else None
381
- ),
382
- country=proxy_response.country or "Unknown",
383
- region=proxy_response.region,
384
- city=proxy_response.city,
385
- status=ProxyStatus(proxy_response.status),
386
- created_at=proxy_response.created_at,
387
- expires_at=proxy_response.expires_at,
388
- last_validated_at=None, # Not in API response
389
- usage_stats=ExtendedProxyUsageStats(
390
- total_requests=proxy_response.usage_stats.total_requests,
391
- successful_requests=proxy_response.usage_stats.successful_requests,
392
- failed_requests=proxy_response.usage_stats.failed_requests,
393
- consecutive_failures=proxy_response.usage_stats.consecutive_failures,
394
- avg_response_time_ms=proxy_response.usage_stats.avg_response_time_ms or 0.0,
395
- last_used_at=proxy_response.usage_stats.last_used_at,
396
- blocked_count=0, # Not in current API
397
- ),
398
- shared=False, # Default
399
- tags=proxy_response.tags or [],
400
- metadata=proxy_response.metadata or {},
401
- # Management fields
402
- is_active=proxy_response.is_healthy or False,
403
- last_health_check=datetime.now(timezone.utc),
404
- blacklisted_until=None,
405
- )
406
-
407
- async def _start_health_monitoring(self) -> None:
408
- """Start background health monitoring task."""
409
- if self._health_check_task is None:
410
- self._health_check_task = asyncio.create_task(self._health_monitor_loop())
411
- self.logger.info("Started proxy health monitoring")
412
-
413
- async def _health_monitor_loop(self) -> None:
414
- """Background task for monitoring proxy health."""
415
- while True:
416
- try:
417
- await self._perform_health_checks()
418
- await asyncio.sleep(self._health_check_interval)
419
- except asyncio.CancelledError:
420
- break
421
- except Exception as e:
422
- self.logger.error(f"Error in health monitor loop: {e}")
423
- await asyncio.sleep(60) # Wait before retrying
424
-
425
- async def _perform_health_checks(self) -> None:
426
- """Perform health checks on all proxies."""
427
- self.logger.debug("Performing proxy health checks...")
428
-
429
- for proxy_id, proxy in self.pool.proxies.items():
430
- try:
431
- await self._check_proxy_health(proxy)
432
- except Exception as e:
433
- self.logger.warning(f"Health check failed for proxy {proxy_id}: {e}")
434
- proxy.metrics.health_status = ProxyHealthStatus.FAILING
435
-
436
- async def _check_proxy_health(self, proxy: ProxyEndpoint) -> None:
437
- """Check health of a specific proxy."""
438
- # Simple health check - in production this would make actual HTTP requests
439
- proxy.last_health_check = datetime.now()
440
-
441
- # Simulate health check logic
442
- if proxy.metrics.consecutive_failures >= 5:
443
- proxy.metrics.health_status = ProxyHealthStatus.BLOCKED
444
- elif proxy.metrics.consecutive_failures >= 3:
445
- proxy.metrics.health_status = ProxyHealthStatus.FAILING
446
- elif proxy.metrics.success_rate < 50:
447
- proxy.metrics.health_status = ProxyHealthStatus.DEGRADED
448
- else:
449
- proxy.metrics.health_status = ProxyHealthStatus.HEALTHY
450
-
451
- @track_development_operation("Proxy Selection", SDKEventType.PROXY_ALLOCATED)
452
- def get_proxy(self, region: Optional[str] = None) -> Optional[ManagedProxy]:
453
- """
454
- Get next proxy for use based on rotation strategy.
455
-
456
- Args:
457
- region: Optional region preference for geographic routing
458
-
459
- Returns:
460
- ManagedProxy if available, None if no proxies available
461
- """
462
- if not self.proxy_config.enabled:
463
- if self.dev_logger:
464
- self.dev_logger.log_warning(
465
- SDKEventType.PROXY_ALLOCATED,
466
- "Proxy allocation requested but proxy management is disabled",
467
- context=SDKContext(component_name="ProxyManager"),
468
- )
469
- return None
470
-
471
- proxy = self.pool.select_proxy(region)
472
- if proxy:
473
- # Update last used timestamp
474
- proxy.usage_stats.last_used_at = datetime.now(timezone.utc).isoformat()
475
- self.logger.debug(f"Selected proxy {proxy.identifier} for use")
476
-
477
- if self.dev_logger:
478
- self.dev_logger.log_info(
479
- SDKEventType.PROXY_ALLOCATED,
480
- f"Proxy allocated: {proxy.identifier}",
481
- context=SDKContext(
482
- component_name="ProxyManager",
483
- metadata={
484
- "proxy_id": proxy.proxy_id,
485
- "region": proxy.region,
486
- "country": proxy.country,
487
- "provider": (
488
- proxy.provider.value
489
- if hasattr(proxy.provider, "value")
490
- else str(proxy.provider)
491
- ),
492
- "success_rate": proxy.usage_stats.success_rate,
493
- "requested_region": region,
494
- },
495
- ),
496
- )
497
- else:
498
- if self.dev_logger:
499
- self.dev_logger.log_error(
500
- SDKEventType.PROXY_ALLOCATED,
501
- f"No available proxies for region: {region or 'any'}",
502
- context=SDKContext(
503
- component_name="ProxyManager",
504
- metadata={
505
- "requested_region": region,
506
- "total_proxies": len(self.pool.proxies),
507
- "available_proxies": len(self.pool.get_available_proxies()),
508
- },
509
- ),
510
- )
511
-
512
- return proxy
513
-
514
- async def record_success(self, proxy: ManagedProxy, response_time_ms: float) -> None:
515
- """Record successful proxy usage and sync with API."""
516
- # Update local stats
517
- proxy.usage_stats.total_requests += 1
518
- proxy.usage_stats.successful_requests += 1
519
- proxy.usage_stats.consecutive_failures = 0
520
-
521
- # Update rolling average response time
522
- if proxy.usage_stats.avg_response_time_ms == 0:
523
- proxy.usage_stats.avg_response_time_ms = response_time_ms
524
- else:
525
- # Simple moving average
526
- proxy.usage_stats.avg_response_time_ms = (
527
- proxy.usage_stats.avg_response_time_ms * 0.8 + response_time_ms * 0.2
528
- )
529
-
530
- proxy.usage_stats.last_used_at = datetime.now(timezone.utc).isoformat()
531
-
532
- # Update global stats
533
- self._successful_requests += 1
534
- self._total_requests += 1
535
-
536
- # Sync with API (non-blocking)
537
- if self._http_client:
538
- try:
539
- # Use auto-generated API service
540
- from unrealon_sdk.src.clients.python_http.models.ProxyUsageRequest import (
541
- ProxyUsageRequest,
542
- )
543
-
544
- usage_request = ProxyUsageRequest(
545
- successful=True,
546
- response_time_ms=response_time_ms,
547
- timestamp=datetime.now(timezone.utc).isoformat(),
548
- )
549
-
550
- await record_proxy_usage_api_v1_proxies__proxy_id__usage_post(
551
- proxy_id=proxy.proxy_id,
552
- body=usage_request,
553
- api_config_override=self._http_client._api_config,
554
- )
555
- except Exception as e:
556
- self.logger.warning(f"Failed to sync success with API: {e}")
557
-
558
- self.logger.debug(
559
- f"Recorded success for proxy {proxy.identifier} ({response_time_ms:.2f}ms)"
560
- )
561
-
562
- if self.dev_logger:
563
- self.dev_logger.log_performance_metric(
564
- "proxy_response_time",
565
- response_time_ms,
566
- "ms",
567
- threshold=5000.0, # 5 second threshold
568
- context=SDKContext(
569
- component_name="ProxyManager",
570
- metadata={
571
- "proxy_id": proxy.proxy_id,
572
- "proxy_identifier": proxy.identifier,
573
- "success_rate": proxy.usage_stats.success_rate,
574
- "total_requests": proxy.usage_stats.total_requests,
575
- },
576
- ),
577
- )
578
-
579
- async def record_failure(self, proxy: ManagedProxy, error: str) -> None:
580
- """Record failed proxy usage and sync with API."""
581
- # Update local stats
582
- proxy.usage_stats.total_requests += 1
583
- proxy.usage_stats.failed_requests += 1
584
- proxy.usage_stats.consecutive_failures += 1
585
- proxy.usage_stats.last_used_at = datetime.now(timezone.utc).isoformat()
586
-
587
- # Update global stats
588
- self._failed_requests += 1
589
- self._total_requests += 1
590
-
591
- # Auto-blacklist if too many consecutive failures
592
- if proxy.usage_stats.consecutive_failures >= 5:
593
- self.pool.blacklist_proxy(proxy.identifier, duration_minutes=60)
594
-
595
- # Report blocked proxy to API
596
- if self._http_client:
597
- try:
598
- block_request = ProxyBlockRequest(
599
- proxy_id=proxy.proxy_id,
600
- reason=f"Consecutive failures: {error}",
601
- block_duration_minutes=60,
602
- )
603
-
604
- await report_blocked_proxy_api_v1_proxies_rotation_block_post(
605
- body=block_request, api_config_override=self._http_client._api_config
606
- )
607
- except Exception as e:
608
- self.logger.warning(f"Failed to report blocked proxy to API: {e}")
609
-
610
- # Sync usage with API (non-blocking)
611
- if self._http_client:
612
- try:
613
- from unrealon_sdk.src.clients.python_http.models.ProxyUsageRequest import (
614
- ProxyUsageRequest,
615
- )
616
-
617
- usage_request = ProxyUsageRequest(
618
- successful=False,
619
- error_message=error,
620
- timestamp=datetime.now(timezone.utc).isoformat(),
621
- )
622
-
623
- await record_proxy_usage_api_v1_proxies__proxy_id__usage_post(
624
- proxy_id=proxy.proxy_id,
625
- body=usage_request,
626
- api_config_override=self._http_client._api_config,
627
- )
628
- except Exception as e:
629
- self.logger.warning(f"Failed to sync failure with API: {e}")
630
-
631
- self.logger.warning(f"Recorded failure for proxy {proxy.identifier}: {error}")
632
-
633
- def get_statistics(self) -> ProxyStatistics:
634
- """Get comprehensive proxy usage statistics using auto-generated model."""
635
- available_proxies = self.pool.get_available_proxies()
636
- blacklisted_count = len([p for p in self.pool.proxies.values() if p.is_blacklisted])
637
-
638
- # Use the auto-generated ProxyStatistics model
639
- return ProxyStatistics(
640
- success=True,
641
- message="Proxy statistics retrieved successfully",
642
- data=None,
643
- timestamp=datetime.now(timezone.utc).isoformat(),
644
- request_id=generate_correlation_id(),
645
- total_proxies=len(self.pool.proxies),
646
- active_proxies=len(available_proxies),
647
- inactive_proxies=len(self.pool.proxies) - len(available_proxies),
648
- blocked_proxies=blacklisted_count,
649
- expired_proxies=0, # TODO: Calculate from expiry dates
650
- error_proxies=0, # TODO: Calculate from error states
651
- healthy_proxies=len([p for p in available_proxies if p.usage_stats.is_healthy]),
652
- degraded_proxies=len([p for p in available_proxies if not p.usage_stats.is_healthy]),
653
- critical_proxies=blacklisted_count,
654
- provider_breakdown={}, # TODO: Calculate provider stats
655
- country_breakdown={}, # TODO: Calculate country stats
656
- overall_success_rate=(
657
- self._successful_requests / self._total_requests * 100
658
- if self._total_requests > 0
659
- else 0.0
660
- ),
661
- avg_response_time_ms=0.0, # TODO: Calculate average from all proxies
662
- total_requests_last_24h=self._total_requests, # Simplified for now
663
- successful_requests_last_24h=self._successful_requests,
664
- expiring_in_24h=0, # TODO: Calculate from expiry dates
665
- expiring_in_7d=0,
666
- expiring_in_30d=0,
667
- most_used_providers=[], # TODO: Calculate top providers
668
- most_active_countries=[], # TODO: Calculate top countries
669
- proxies_added_last_24h=0, # TODO: Track new additions
670
- proxies_blocked_last_24h=blacklisted_count,
671
- generated_at=datetime.now(timezone.utc).isoformat(),
672
- )
673
-
674
- async def rotate_proxies(self, provider: Optional[str] = None) -> int:
675
- """
676
- Force rotation of proxies from provider.
677
-
678
- Args:
679
- provider: Optional provider to rotate, None for all providers
680
-
681
- Returns:
682
- Number of proxies rotated
683
- """
684
- rotated = 0
685
-
686
- for proxy_id in list(self.pool.proxies.keys()):
687
- proxy = self.pool.proxies[proxy_id]
688
- if provider is None or proxy.provider == provider:
689
- self.pool.remove_proxy(proxy_id)
690
- rotated += 1
691
-
692
- # Reload proxies from providers
693
- await self._load_initial_proxies()
694
-
695
- self.logger.info(f"Rotated {rotated} proxies")
696
- return rotated