unrealon 1.0.9__py3-none-any.whl → 1.1.0__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.0.dist-info/METADATA +164 -0
  3. unrealon-1.1.0.dist-info/RECORD +82 -0
  4. {unrealon-1.0.9.dist-info → unrealon-1.1.0.dist-info}/WHEEL +1 -1
  5. unrealon-1.1.0.dist-info/entry_points.txt +9 -0
  6. {unrealon-1.0.9.dist-info → unrealon-1.1.0.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
@@ -0,0 +1,75 @@
1
+ """
2
+ Proxy-related RPC handlers.
3
+ """
4
+
5
+ import uuid
6
+ from unrealon_rpc.logging import get_logger
7
+
8
+ from ...models import (
9
+ ProxyInfo,
10
+ ProxyAllocateRequest, ProxyAllocateResponse,
11
+ ProxyReleaseRequest, ProxyReleaseResponse,
12
+ ProxyCheckRequest, ProxyCheckResponse
13
+ )
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class ProxyHandlers:
19
+ """Handlers for proxy-related RPC operations."""
20
+
21
+ async def handle_proxy_allocate(self, parser_id: str, proxy_type: str, location: str = None) -> dict:
22
+ """Handle proxy allocation."""
23
+ try:
24
+ # Create request object for validation
25
+ request = ProxyAllocateRequest(
26
+ parser_id=parser_id,
27
+ proxy_type=proxy_type,
28
+ location=location
29
+ )
30
+
31
+ # Proxy allocation should be implemented by external service
32
+ proxy_info = ProxyInfo(
33
+ proxy_id=str(uuid.uuid4()),
34
+ parser_id=request.parser_id,
35
+ host="127.0.0.1",
36
+ port=8080,
37
+ proxy_type=request.proxy_type,
38
+ location=request.location
39
+ )
40
+
41
+ self.proxies[proxy_info.proxy_id] = proxy_info
42
+
43
+ logger.info(f"Proxy allocated: {proxy_info.proxy_id} for {request.parser_id}")
44
+
45
+ response = ProxyAllocateResponse(success=True, proxy=proxy_info)
46
+ return response.model_dump(mode='json')
47
+
48
+ except Exception as e:
49
+ response = ProxyAllocateResponse(success=False, error=str(e))
50
+ return response.model_dump(mode='json')
51
+
52
+ async def handle_proxy_release(self, proxy_id: str) -> dict:
53
+ """Handle proxy release."""
54
+ try:
55
+ # Create request object for validation
56
+ request = ProxyReleaseRequest(proxy_id=proxy_id)
57
+
58
+ if request.proxy_id in self.proxies:
59
+ del self.proxies[request.proxy_id]
60
+ logger.info(f"Proxy released: {request.proxy_id}")
61
+
62
+ response = ProxyReleaseResponse(success=True, proxy_id=request.proxy_id, message="Proxy released")
63
+ return response.model_dump(mode='json')
64
+ except Exception as e:
65
+ logger.error(f"Proxy release failed: {e}")
66
+ response = ProxyReleaseResponse(success=False, proxy_id=proxy_id, error=str(e))
67
+ return response.model_dump(mode='json')
68
+
69
+ async def handle_proxy_check(self, request: ProxyCheckRequest) -> ProxyCheckResponse:
70
+ """Handle proxy health check."""
71
+ if request.proxy_id not in self.proxies:
72
+ return ProxyCheckResponse(success=False, error="Proxy not found")
73
+
74
+ # Proxy health check should be implemented by external service
75
+ return ProxyCheckResponse(success=True, proxy_id=request.proxy_id, status="healthy")
@@ -0,0 +1,545 @@
1
+ """
2
+ Scheduler RPC handlers for Parser Bridge Server.
3
+
4
+ Handles scheduler-related RPC operations including task management,
5
+ cron scheduling, and parser status tracking.
6
+ """
7
+
8
+ from typing import Dict, Any, List, Optional
9
+ from datetime import datetime, timedelta
10
+
11
+ from unrealon_rpc.logging import get_logger
12
+ from unrealon_bridge.models.scheduler import (
13
+ ScheduledTask,
14
+ TaskParameters,
15
+ TaskPriority,
16
+ ScheduleType,
17
+ CronExpression,
18
+ TaskRetryConfig,
19
+ TaskExecutionResult,
20
+ ParserStatus,
21
+ TaskQueue,
22
+ SchedulerError,
23
+ TaskValidationError,
24
+ TaskExecutionError,
25
+ )
26
+ from unrealon_bridge.models.responses import BaseRPCResponse
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ class SchedulerTaskCreateResponse(BaseRPCResponse):
32
+ """Response for task creation."""
33
+ task_id: Optional[str] = None
34
+ scheduled_at: Optional[datetime] = None
35
+ next_run: Optional[datetime] = None
36
+
37
+
38
+ class SchedulerTaskListResponse(BaseRPCResponse):
39
+ """Response for task listing."""
40
+ tasks: List[ScheduledTask]
41
+ total_count: int
42
+
43
+
44
+ class SchedulerTaskStatusResponse(BaseRPCResponse):
45
+ """Response for task status."""
46
+ task: ScheduledTask
47
+ execution_history: List[TaskExecutionResult]
48
+
49
+
50
+ class SchedulerParserStatusResponse(BaseRPCResponse):
51
+ """Response for parser status."""
52
+ parser_status: ParserStatus
53
+ active_tasks: List[str]
54
+
55
+
56
+ class SchedulerStatsResponse(BaseRPCResponse):
57
+ """Response for scheduler statistics."""
58
+ total_tasks: int
59
+ active_tasks: int
60
+ completed_tasks: int
61
+ failed_tasks: int
62
+ parsers_online: int
63
+ parsers_offline: int
64
+
65
+
66
+ # In-memory storage for demonstration (in production, use Redis/Database)
67
+ _scheduled_tasks: Dict[str, ScheduledTask] = {}
68
+ _parser_statuses: Dict[str, ParserStatus] = {}
69
+ _task_execution_history: Dict[str, List[TaskExecutionResult]] = {}
70
+
71
+
72
+ class SchedulerHandlers:
73
+ """Scheduler RPC handlers."""
74
+
75
+ async def handle_scheduler_create_task(self, parser_id: str, task_type: str, parameters: dict, cron_expression: str = None, scheduled_at: str = None, retry_config: dict = None, priority: int = 5, timeout_seconds: int = 300, api_key: str = None) -> Dict[str, Any]:
76
+ """Create a new scheduled task."""
77
+ return await handle_scheduler_create_task(parser_id, task_type, parameters, cron_expression, scheduled_at, retry_config, priority, timeout_seconds, api_key)
78
+
79
+ async def handle_scheduler_list_tasks(self, parser_id: str = None, task_type: str = None, status: str = None, limit: int = 100, offset: int = 0, api_key: str = None) -> Dict[str, Any]:
80
+ """List scheduled tasks."""
81
+ return await handle_scheduler_list_tasks(parser_id, task_type, status, limit, offset, api_key)
82
+
83
+ async def handle_scheduler_get_task(self, **params) -> Dict[str, Any]:
84
+ """Get task status and execution history."""
85
+ return await handle_scheduler_get_task(**params)
86
+
87
+ async def handle_scheduler_cancel_task(self, **params) -> Dict[str, Any]:
88
+ """Cancel a scheduled task."""
89
+ return await handle_scheduler_cancel_task(**params)
90
+
91
+ async def handle_scheduler_update_parser_status(self, parser_id: str, status: str, last_seen: str = None, current_task_id: str = None, capabilities: list = None, api_key: str = None) -> Dict[str, Any]:
92
+ """Update parser status for scheduler."""
93
+ return await handle_scheduler_update_parser_status(parser_id, status, last_seen, current_task_id, capabilities, api_key)
94
+
95
+ async def handle_scheduler_get_parser_status(self, **params) -> Dict[str, Any]:
96
+ """Get parser status and active tasks."""
97
+ return await handle_scheduler_get_parser_status(**params)
98
+
99
+ async def handle_scheduler_get_stats(self, api_key: str = None) -> Dict[str, Any]:
100
+ """Get scheduler statistics."""
101
+ return await handle_scheduler_get_stats(api_key)
102
+
103
+
104
+ async def handle_scheduler_create_task(parser_id: str, task_type: str, parameters: dict, cron_expression: str = None, scheduled_at: str = None, retry_config: dict = None, priority: int = 5, timeout_seconds: int = 300, api_key: str = None) -> Dict[str, Any]:
105
+ """
106
+ Create a new scheduled task.
107
+
108
+ Expected params:
109
+ parser_id: str
110
+ task_type: str (command, scrape, parse, etc.)
111
+ parameters: TaskParameters
112
+ cron_expression: Optional[str]
113
+ scheduled_at: Optional[datetime]
114
+ retry_config: Optional[TaskRetryConfig]
115
+ priority: Optional[int]
116
+ timeout_seconds: Optional[int]
117
+ api_key: Optional[str]
118
+ """
119
+ try:
120
+ # Validate required parameters
121
+ if not parser_id or not task_type:
122
+ return SchedulerTaskCreateResponse(
123
+ success=False,
124
+ error="parser_id and task_type are required"
125
+ ).model_dump(mode='json')
126
+
127
+ # Create TaskParameters
128
+ try:
129
+ task_parameters = TaskParameters.model_validate(parameters)
130
+ except Exception as e:
131
+ raise TaskValidationError(f"Invalid task parameters: {e}")
132
+
133
+ # Handle cron expression if provided
134
+ cron_expr = None
135
+ if cron_expression:
136
+ try:
137
+ cron_expr = CronExpression(expression=cron_expression)
138
+ except Exception as e:
139
+ raise TaskValidationError(f"Invalid cron expression: {e}")
140
+
141
+ # Handle retry config if provided
142
+ retry_cfg = None
143
+ if retry_config:
144
+ try:
145
+ retry_cfg = TaskRetryConfig.model_validate(retry_config)
146
+ except Exception as e:
147
+ raise TaskValidationError(f"Invalid retry config: {e}")
148
+
149
+ # Handle scheduled_at if provided
150
+ scheduled_datetime = None
151
+ if scheduled_at:
152
+ try:
153
+ scheduled_datetime = datetime.fromisoformat(scheduled_at)
154
+ except Exception as e:
155
+ raise TaskValidationError(f"Invalid scheduled_at format: {e}")
156
+
157
+ # Determine schedule type
158
+ if cron_expr:
159
+ schedule_type = ScheduleType.RECURRING
160
+ elif scheduled_datetime:
161
+ schedule_type = ScheduleType.DELAYED
162
+ else:
163
+ schedule_type = ScheduleType.IMMEDIATE
164
+
165
+ # Create scheduled task
166
+ task_data = {
167
+ "task_name": f"{task_type}_{parser_id}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}",
168
+ "parser_type": task_type, # Using task_type as parser_type for now
169
+ "parser_id": parser_id,
170
+ "task_parameters": task_parameters,
171
+ "priority": TaskPriority(priority) if priority in [1, 3, 5, 7, 9] else TaskPriority.NORMAL,
172
+ "schedule_type": schedule_type,
173
+ }
174
+
175
+ # Add optional fields based on schedule type
176
+ if cron_expr:
177
+ task_data["cron_schedule"] = cron_expr
178
+ if scheduled_datetime:
179
+ task_data["scheduled_at"] = scheduled_datetime
180
+ if retry_cfg:
181
+ task_data["retry_config"] = retry_cfg
182
+
183
+ task = ScheduledTask(**task_data)
184
+
185
+ # Store task
186
+ _scheduled_tasks[task.task_id] = task
187
+ _task_execution_history[task.task_id] = []
188
+
189
+ logger.info(
190
+ f"Created scheduled task: {task.task_id}",
191
+ component="scheduler",
192
+ operation="create_task",
193
+ parser_id=parser_id,
194
+ task_type=task_type,
195
+ api_key=api_key[:8] + "..." if api_key else None
196
+ )
197
+
198
+ return SchedulerTaskCreateResponse(
199
+ success=True,
200
+ task_id=task.task_id,
201
+ scheduled_at=task.scheduled_at,
202
+ next_run=task.scheduled_at # For now, use scheduled_at as next_run
203
+ ).model_dump(mode='json')
204
+
205
+ except (TaskValidationError, SchedulerError) as e:
206
+ logger.error(f"Task creation failed: {e}", component="scheduler", operation="create_task")
207
+ return SchedulerTaskCreateResponse(
208
+ success=False,
209
+ error=str(e)
210
+ ).model_dump(mode='json')
211
+ except Exception as e:
212
+ logger.error(f"Unexpected error creating task: {e}", component="scheduler", operation="create_task", error=e)
213
+ return SchedulerTaskCreateResponse(
214
+ success=False,
215
+ error="Internal server error"
216
+ ).model_dump(mode='json')
217
+
218
+
219
+ async def handle_scheduler_list_tasks(parser_id: str = None, task_type: str = None, status: str = None, limit: int = 100, offset: int = 0, api_key: str = None) -> Dict[str, Any]:
220
+ """
221
+ List scheduled tasks.
222
+
223
+ Expected params:
224
+ parser_id: Optional[str] - filter by parser
225
+ task_type: Optional[str] - filter by task type
226
+ status: Optional[str] - filter by status
227
+ limit: Optional[int] - limit results
228
+ offset: Optional[int] - offset for pagination
229
+ api_key: Optional[str]
230
+ """
231
+ try:
232
+
233
+ # Filter tasks
234
+ filtered_tasks = []
235
+ for task in _scheduled_tasks.values():
236
+ if parser_id and task.parser_id != parser_id:
237
+ continue
238
+ if task_type and task.task_type != task_type:
239
+ continue
240
+ if status and task.status != status:
241
+ continue
242
+ filtered_tasks.append(task)
243
+
244
+ # Sort by created_at (newest first)
245
+ filtered_tasks.sort(key=lambda t: t.created_at, reverse=True)
246
+
247
+ # Apply pagination
248
+ total_count = len(filtered_tasks)
249
+ paginated_tasks = filtered_tasks[offset:offset + limit]
250
+
251
+ logger.info(
252
+ f"Listed {len(paginated_tasks)} tasks (total: {total_count})",
253
+ component="scheduler",
254
+ operation="list_tasks",
255
+ parser_id=parser_id,
256
+ task_type=task_type,
257
+ status=status
258
+ )
259
+
260
+ return SchedulerTaskListResponse(
261
+ success=True,
262
+ tasks=paginated_tasks,
263
+ total_count=total_count
264
+ ).model_dump(mode='json')
265
+
266
+ except Exception as e:
267
+ logger.error(f"Error listing tasks: {e}", component="scheduler", operation="list_tasks", error=e)
268
+ return SchedulerTaskListResponse(
269
+ success=False,
270
+ error="Internal server error",
271
+ tasks=[],
272
+ total_count=0
273
+ ).model_dump(mode='json')
274
+
275
+
276
+ async def handle_scheduler_get_task(**params) -> Dict[str, Any]:
277
+ """
278
+ Get task status and execution history.
279
+
280
+ Expected params:
281
+ task_id: str
282
+ api_key: Optional[str]
283
+ """
284
+ try:
285
+ task_id = params.get("task_id")
286
+ if not task_id:
287
+ return SchedulerTaskStatusResponse(
288
+ success=False,
289
+ error="task_id is required",
290
+ task=None,
291
+ execution_history=[]
292
+ ).model_dump(mode='json')
293
+
294
+ task = _scheduled_tasks.get(task_id)
295
+ if not task:
296
+ raise TaskExecutionError(f"Task not found: {task_id}")
297
+
298
+ execution_history = _task_execution_history.get(task_id, [])
299
+
300
+ logger.info(
301
+ f"Retrieved task: {task_id}",
302
+ component="scheduler",
303
+ operation="get_task",
304
+ task_status=task.status
305
+ )
306
+
307
+ return SchedulerTaskStatusResponse(
308
+ success=True,
309
+ task=task,
310
+ execution_history=execution_history
311
+ ).model_dump(mode='json')
312
+
313
+ except TaskExecutionError as e:
314
+ logger.warning(f"Task not found: {e}", component="scheduler", operation="get_task")
315
+ return SchedulerTaskStatusResponse(
316
+ success=False,
317
+ error=str(e),
318
+ task=None,
319
+ execution_history=[]
320
+ ).model_dump(mode='json')
321
+ except Exception as e:
322
+ logger.error(f"Error getting task: {e}", component="scheduler", operation="get_task", error=e)
323
+ return SchedulerTaskStatusResponse(
324
+ success=False,
325
+ error="Internal server error",
326
+ task=None,
327
+ execution_history=[]
328
+ ).model_dump(mode='json')
329
+
330
+
331
+ async def handle_scheduler_cancel_task(**params) -> Dict[str, Any]:
332
+ """
333
+ Cancel a scheduled task.
334
+
335
+ Expected params:
336
+ task_id: str
337
+ api_key: Optional[str]
338
+ """
339
+ try:
340
+ task_id = params.get("task_id")
341
+ if not task_id:
342
+ return BaseRPCResponse(
343
+ success=False,
344
+ error="task_id is required"
345
+ ).model_dump(mode='json')
346
+
347
+ task = _scheduled_tasks.get(task_id)
348
+ if not task:
349
+ raise TaskExecutionError(f"Task not found: {task_id}")
350
+
351
+ # Update task status
352
+ task.status = "cancelled"
353
+ task.updated_at = datetime.utcnow()
354
+
355
+ logger.info(
356
+ f"Cancelled task: {task_id}",
357
+ component="scheduler",
358
+ operation="cancel_task",
359
+ parser_id=task.parser_id
360
+ )
361
+
362
+ return BaseRPCResponse(
363
+ success=True,
364
+ message=f"Task {task_id} cancelled successfully"
365
+ ).model_dump(mode='json')
366
+
367
+ except TaskExecutionError as e:
368
+ logger.warning(f"Task not found: {e}", component="scheduler", operation="cancel_task")
369
+ return BaseRPCResponse(
370
+ success=False,
371
+ error=str(e)
372
+ ).model_dump(mode='json')
373
+ except Exception as e:
374
+ logger.error(f"Error cancelling task: {e}", component="scheduler", operation="cancel_task", error=e)
375
+ return BaseRPCResponse(
376
+ success=False,
377
+ error="Internal server error"
378
+ ).model_dump(mode='json')
379
+
380
+
381
+ async def handle_scheduler_update_parser_status(parser_id: str, status: str, last_seen: str = None, current_task_id: str = None, capabilities: list = None, api_key: str = None) -> Dict[str, Any]:
382
+ """
383
+ Update parser status for scheduler.
384
+
385
+ Expected params:
386
+ parser_id: str
387
+ status: str (online, offline, busy, error)
388
+ last_seen: Optional[datetime]
389
+ current_task_id: Optional[str]
390
+ capabilities: Optional[List[str]]
391
+ api_key: Optional[str]
392
+ """
393
+ try:
394
+ if not parser_id or not status:
395
+ return BaseRPCResponse(
396
+ success=False,
397
+ error="parser_id and status are required"
398
+ ).model_dump(mode='json')
399
+
400
+ # Handle last_seen
401
+ last_seen_datetime = datetime.utcnow()
402
+ if last_seen:
403
+ try:
404
+ last_seen_datetime = datetime.fromisoformat(last_seen)
405
+ except Exception:
406
+ pass # Use current time if parsing fails
407
+
408
+ # Create or update parser status
409
+ parser_status = ParserStatus(
410
+ parser_id=parser_id,
411
+ parser_type="generic", # Default parser type
412
+ status=status,
413
+ last_seen=last_seen_datetime,
414
+ capabilities=capabilities or []
415
+ )
416
+
417
+ _parser_statuses[parser_id] = parser_status
418
+
419
+ logger.info(
420
+ f"Updated parser status: {parser_id} -> {status}",
421
+ component="scheduler",
422
+ operation="update_parser_status",
423
+ parser_id=parser_id,
424
+ status=status
425
+ )
426
+
427
+ return BaseRPCResponse(
428
+ success=True,
429
+ message=f"Parser {parser_id} status updated to {status}"
430
+ ).model_dump(mode='json')
431
+
432
+ except Exception as e:
433
+ logger.error(f"Error updating parser status: {e}", component="scheduler", operation="update_parser_status", error=e)
434
+ return BaseRPCResponse(
435
+ success=False,
436
+ error="Internal server error"
437
+ ).model_dump(mode='json')
438
+
439
+
440
+ async def handle_scheduler_get_parser_status(**params) -> Dict[str, Any]:
441
+ """
442
+ Get parser status and active tasks.
443
+
444
+ Expected params:
445
+ parser_id: str
446
+ api_key: Optional[str]
447
+ """
448
+ try:
449
+ parser_id = params.get("parser_id")
450
+ if not parser_id:
451
+ return SchedulerParserStatusResponse(
452
+ success=False,
453
+ error="parser_id is required",
454
+ parser_status=None,
455
+ active_tasks=[]
456
+ ).model_dump(mode='json')
457
+
458
+ parser_status = _parser_statuses.get(parser_id)
459
+ if not parser_status:
460
+ return SchedulerParserStatusResponse(
461
+ success=False,
462
+ error=f"Parser not found: {parser_id}",
463
+ parser_status=None,
464
+ active_tasks=[]
465
+ ).model_dump(mode='json')
466
+
467
+ # Find active tasks for this parser
468
+ active_tasks = []
469
+ for task in _scheduled_tasks.values():
470
+ if task.parser_id == parser_id and task.status in ["pending", "running"]:
471
+ active_tasks.append(task.task_id)
472
+
473
+ logger.info(
474
+ f"Retrieved parser status: {parser_id}",
475
+ component="scheduler",
476
+ operation="get_parser_status",
477
+ parser_status=parser_status.status,
478
+ active_tasks_count=len(active_tasks)
479
+ )
480
+
481
+ return SchedulerParserStatusResponse(
482
+ success=True,
483
+ parser_status=parser_status,
484
+ active_tasks=active_tasks
485
+ ).model_dump(mode='json')
486
+
487
+ except Exception as e:
488
+ logger.error(f"Error getting parser status: {e}", component="scheduler", operation="get_parser_status", error=e)
489
+ return SchedulerParserStatusResponse(
490
+ success=False,
491
+ error="Internal server error",
492
+ parser_status=None,
493
+ active_tasks=[]
494
+ ).model_dump(mode='json')
495
+
496
+
497
+ async def handle_scheduler_get_stats(api_key: str = None) -> Dict[str, Any]:
498
+ """
499
+ Get scheduler statistics.
500
+
501
+ Expected params:
502
+ api_key: Optional[str]
503
+ """
504
+ try:
505
+ # Count tasks by status
506
+ total_tasks = len(_scheduled_tasks)
507
+ active_tasks = sum(1 for task in _scheduled_tasks.values() if task.status in ["pending", "running"])
508
+ completed_tasks = sum(1 for task in _scheduled_tasks.values() if task.status == "completed")
509
+ failed_tasks = sum(1 for task in _scheduled_tasks.values() if task.status == "failed")
510
+
511
+ # Count parsers by status
512
+ parsers_online = sum(1 for parser in _parser_statuses.values() if parser.status == "online")
513
+ parsers_offline = sum(1 for parser in _parser_statuses.values() if parser.status == "offline")
514
+
515
+ logger.info(
516
+ "Retrieved scheduler statistics",
517
+ component="scheduler",
518
+ operation="get_stats",
519
+ total_tasks=total_tasks,
520
+ active_tasks=active_tasks,
521
+ parsers_online=parsers_online
522
+ )
523
+
524
+ return SchedulerStatsResponse(
525
+ success=True,
526
+ total_tasks=total_tasks,
527
+ active_tasks=active_tasks,
528
+ completed_tasks=completed_tasks,
529
+ failed_tasks=failed_tasks,
530
+ parsers_online=parsers_online,
531
+ parsers_offline=parsers_offline
532
+ ).model_dump(mode='json')
533
+
534
+ except Exception as e:
535
+ logger.error(f"Error getting scheduler stats: {e}", component="scheduler", operation="get_stats", error=e)
536
+ return SchedulerStatsResponse(
537
+ success=False,
538
+ error="Internal server error",
539
+ total_tasks=0,
540
+ active_tasks=0,
541
+ completed_tasks=0,
542
+ failed_tasks=0,
543
+ parsers_online=0,
544
+ parsers_offline=0
545
+ ).model_dump(mode='json')
@@ -0,0 +1,66 @@
1
+ """
2
+ Session-related RPC handlers.
3
+ """
4
+
5
+ import uuid
6
+ from datetime import datetime
7
+ from unrealon_rpc.logging import get_logger
8
+
9
+ from ...models import (
10
+ ParserSession,
11
+ SessionStartRequest, SessionStartResponse,
12
+ SessionEndRequest, SessionEndResponse
13
+ )
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class SessionHandlers:
19
+ """Handlers for session-related RPC operations."""
20
+
21
+ async def handle_session_start(self, parser_id: str, session_type: str, metadata: dict = None) -> dict:
22
+ """Handle session start."""
23
+ try:
24
+ # Create request object for validation
25
+ request = SessionStartRequest(
26
+ parser_id=parser_id,
27
+ session_type=session_type,
28
+ metadata=metadata
29
+ )
30
+
31
+ session = ParserSession(
32
+ session_id=str(uuid.uuid4()),
33
+ parser_id=request.parser_id,
34
+ session_type=request.session_type,
35
+ metadata=request.metadata or {}
36
+ )
37
+ self.sessions[session.session_id] = session
38
+
39
+ logger.info(f"Session started: {session.session_id} for parser {session.parser_id}")
40
+
41
+ response = SessionStartResponse(success=True, session=session)
42
+ return response.model_dump(mode='json')
43
+ except Exception as e:
44
+ logger.error(f"Session start failed: {e}")
45
+ response = SessionStartResponse(success=False, error=str(e))
46
+ return response.model_dump(mode='json')
47
+
48
+ async def handle_session_end(self, session_id: str) -> dict:
49
+ """Handle session end."""
50
+ try:
51
+ # Create request object for validation
52
+ request = SessionEndRequest(session_id=session_id)
53
+
54
+ if request.session_id in self.sessions:
55
+ session = self.sessions[request.session_id]
56
+ session.ended_at = datetime.now()
57
+ session.status = "completed"
58
+
59
+ logger.info(f"Session ended: {request.session_id}")
60
+
61
+ response = SessionEndResponse(success=True, session_id=request.session_id, message="Session ended")
62
+ return response.model_dump(mode='json')
63
+ except Exception as e:
64
+ logger.error(f"Session end failed: {e}")
65
+ response = SessionEndResponse(success=False, session_id=session_id, error=str(e))
66
+ return response.model_dump(mode='json')