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.
- unrealon/__init__.py +23 -21
- unrealon-1.1.0.dist-info/METADATA +164 -0
- unrealon-1.1.0.dist-info/RECORD +82 -0
- {unrealon-1.0.9.dist-info → unrealon-1.1.0.dist-info}/WHEEL +1 -1
- unrealon-1.1.0.dist-info/entry_points.txt +9 -0
- {unrealon-1.0.9.dist-info → unrealon-1.1.0.dist-info/licenses}/LICENSE +1 -1
- unrealon_bridge/__init__.py +114 -0
- unrealon_bridge/cli.py +316 -0
- unrealon_bridge/client/__init__.py +93 -0
- unrealon_bridge/client/base.py +78 -0
- unrealon_bridge/client/commands.py +89 -0
- unrealon_bridge/client/connection.py +90 -0
- unrealon_bridge/client/events.py +65 -0
- unrealon_bridge/client/health.py +38 -0
- unrealon_bridge/client/html_parser.py +146 -0
- unrealon_bridge/client/logging.py +139 -0
- unrealon_bridge/client/proxy.py +70 -0
- unrealon_bridge/client/scheduler.py +450 -0
- unrealon_bridge/client/session.py +70 -0
- unrealon_bridge/configs/__init__.py +14 -0
- unrealon_bridge/configs/bridge_config.py +212 -0
- unrealon_bridge/configs/bridge_config.yaml +39 -0
- unrealon_bridge/models/__init__.py +138 -0
- unrealon_bridge/models/base.py +28 -0
- unrealon_bridge/models/command.py +41 -0
- unrealon_bridge/models/events.py +40 -0
- unrealon_bridge/models/html_parser.py +79 -0
- unrealon_bridge/models/logging.py +55 -0
- unrealon_bridge/models/parser.py +63 -0
- unrealon_bridge/models/proxy.py +41 -0
- unrealon_bridge/models/requests.py +95 -0
- unrealon_bridge/models/responses.py +88 -0
- unrealon_bridge/models/scheduler.py +592 -0
- unrealon_bridge/models/session.py +28 -0
- unrealon_bridge/server/__init__.py +91 -0
- unrealon_bridge/server/base.py +171 -0
- unrealon_bridge/server/handlers/__init__.py +23 -0
- unrealon_bridge/server/handlers/command.py +110 -0
- unrealon_bridge/server/handlers/html_parser.py +139 -0
- unrealon_bridge/server/handlers/logging.py +95 -0
- unrealon_bridge/server/handlers/parser.py +95 -0
- unrealon_bridge/server/handlers/proxy.py +75 -0
- unrealon_bridge/server/handlers/scheduler.py +545 -0
- unrealon_bridge/server/handlers/session.py +66 -0
- unrealon_browser/__init__.py +61 -18
- unrealon_browser/{src/cli → cli}/browser_cli.py +6 -13
- unrealon_browser/{src/cli → cli}/cookies_cli.py +5 -1
- unrealon_browser/{src/core → core}/browser_manager.py +2 -2
- unrealon_browser/{src/managers → managers}/captcha.py +1 -1
- unrealon_browser/{src/managers → managers}/cookies.py +1 -1
- unrealon_browser/managers/logger_bridge.py +231 -0
- unrealon_browser/{src/managers → managers}/profile.py +1 -1
- unrealon_driver/__init__.py +73 -19
- unrealon_driver/browser/__init__.py +8 -0
- unrealon_driver/browser/config.py +74 -0
- unrealon_driver/browser/manager.py +416 -0
- unrealon_driver/exceptions.py +28 -0
- unrealon_driver/parser/__init__.py +55 -0
- unrealon_driver/parser/cli_manager.py +141 -0
- unrealon_driver/parser/daemon_manager.py +227 -0
- unrealon_driver/parser/managers/__init__.py +46 -0
- unrealon_driver/parser/managers/browser.py +51 -0
- unrealon_driver/parser/managers/config.py +281 -0
- unrealon_driver/parser/managers/error.py +412 -0
- unrealon_driver/parser/managers/html.py +732 -0
- unrealon_driver/parser/managers/logging.py +609 -0
- unrealon_driver/parser/managers/result.py +321 -0
- unrealon_driver/parser/parser_manager.py +628 -0
- unrealon/sdk_config.py +0 -88
- unrealon-1.0.9.dist-info/METADATA +0 -810
- unrealon-1.0.9.dist-info/RECORD +0 -246
- unrealon_browser/pyproject.toml +0 -182
- unrealon_browser/src/__init__.py +0 -62
- unrealon_browser/src/managers/logger_bridge.py +0 -395
- unrealon_driver/README.md +0 -204
- unrealon_driver/pyproject.toml +0 -187
- unrealon_driver/src/__init__.py +0 -90
- unrealon_driver/src/cli/__init__.py +0 -10
- unrealon_driver/src/cli/main.py +0 -66
- unrealon_driver/src/cli/simple.py +0 -510
- unrealon_driver/src/config/__init__.py +0 -11
- unrealon_driver/src/config/auto_config.py +0 -478
- unrealon_driver/src/core/__init__.py +0 -18
- unrealon_driver/src/core/exceptions.py +0 -289
- unrealon_driver/src/core/parser.py +0 -638
- unrealon_driver/src/dto/__init__.py +0 -66
- unrealon_driver/src/dto/cli.py +0 -119
- unrealon_driver/src/dto/config.py +0 -18
- unrealon_driver/src/dto/events.py +0 -237
- unrealon_driver/src/dto/execution.py +0 -313
- unrealon_driver/src/dto/services.py +0 -311
- unrealon_driver/src/execution/__init__.py +0 -23
- unrealon_driver/src/execution/daemon_mode.py +0 -317
- unrealon_driver/src/execution/interactive_mode.py +0 -88
- unrealon_driver/src/execution/modes.py +0 -45
- unrealon_driver/src/execution/scheduled_mode.py +0 -209
- unrealon_driver/src/execution/test_mode.py +0 -250
- unrealon_driver/src/logging/__init__.py +0 -24
- unrealon_driver/src/logging/driver_logger.py +0 -512
- unrealon_driver/src/services/__init__.py +0 -24
- unrealon_driver/src/services/browser_service.py +0 -726
- unrealon_driver/src/services/llm/__init__.py +0 -15
- unrealon_driver/src/services/llm/browser_llm_service.py +0 -363
- unrealon_driver/src/services/llm/llm.py +0 -195
- unrealon_driver/src/services/logger_service.py +0 -232
- unrealon_driver/src/services/metrics_service.py +0 -185
- unrealon_driver/src/services/scheduler_service.py +0 -489
- unrealon_driver/src/services/websocket_service.py +0 -362
- unrealon_driver/src/utils/__init__.py +0 -16
- unrealon_driver/src/utils/service_factory.py +0 -317
- unrealon_driver/src/utils/time_formatter.py +0 -338
- unrealon_llm/README.md +0 -44
- unrealon_llm/__init__.py +0 -26
- unrealon_llm/pyproject.toml +0 -154
- unrealon_llm/src/__init__.py +0 -228
- unrealon_llm/src/cli/__init__.py +0 -0
- unrealon_llm/src/core/__init__.py +0 -11
- unrealon_llm/src/core/smart_client.py +0 -438
- unrealon_llm/src/dto/__init__.py +0 -155
- unrealon_llm/src/dto/models/__init__.py +0 -0
- unrealon_llm/src/dto/models/config.py +0 -343
- unrealon_llm/src/dto/models/core.py +0 -328
- unrealon_llm/src/dto/models/enums.py +0 -123
- unrealon_llm/src/dto/models/html_analysis.py +0 -345
- unrealon_llm/src/dto/models/statistics.py +0 -473
- unrealon_llm/src/dto/models/translation.py +0 -383
- unrealon_llm/src/dto/models/type_conversion.py +0 -462
- unrealon_llm/src/dto/schemas/__init__.py +0 -0
- unrealon_llm/src/exceptions.py +0 -392
- unrealon_llm/src/llm_config/__init__.py +0 -20
- unrealon_llm/src/llm_config/logging_config.py +0 -178
- unrealon_llm/src/llm_logging/__init__.py +0 -42
- unrealon_llm/src/llm_logging/llm_events.py +0 -107
- unrealon_llm/src/llm_logging/llm_logger.py +0 -466
- unrealon_llm/src/managers/__init__.py +0 -15
- unrealon_llm/src/managers/cache_manager.py +0 -67
- unrealon_llm/src/managers/cost_manager.py +0 -107
- unrealon_llm/src/managers/request_manager.py +0 -298
- unrealon_llm/src/modules/__init__.py +0 -0
- unrealon_llm/src/modules/html_processor/__init__.py +0 -25
- unrealon_llm/src/modules/html_processor/base_processor.py +0 -415
- unrealon_llm/src/modules/html_processor/details_processor.py +0 -85
- unrealon_llm/src/modules/html_processor/listing_processor.py +0 -91
- unrealon_llm/src/modules/html_processor/models/__init__.py +0 -20
- unrealon_llm/src/modules/html_processor/models/processing_models.py +0 -40
- unrealon_llm/src/modules/html_processor/models/universal_model.py +0 -56
- unrealon_llm/src/modules/html_processor/processor.py +0 -102
- unrealon_llm/src/modules/llm/__init__.py +0 -0
- unrealon_llm/src/modules/translator/__init__.py +0 -0
- unrealon_llm/src/provider.py +0 -116
- unrealon_llm/src/utils/__init__.py +0 -95
- unrealon_llm/src/utils/common.py +0 -64
- unrealon_llm/src/utils/data_extractor.py +0 -188
- unrealon_llm/src/utils/html_cleaner.py +0 -767
- unrealon_llm/src/utils/language_detector.py +0 -308
- unrealon_llm/src/utils/models_cache.py +0 -592
- unrealon_llm/src/utils/smart_counter.py +0 -229
- unrealon_llm/src/utils/token_counter.py +0 -189
- unrealon_sdk/README.md +0 -25
- unrealon_sdk/__init__.py +0 -30
- unrealon_sdk/pyproject.toml +0 -231
- unrealon_sdk/src/__init__.py +0 -150
- unrealon_sdk/src/cli/__init__.py +0 -12
- unrealon_sdk/src/cli/commands/__init__.py +0 -22
- unrealon_sdk/src/cli/commands/benchmark.py +0 -42
- unrealon_sdk/src/cli/commands/diagnostics.py +0 -573
- unrealon_sdk/src/cli/commands/health.py +0 -46
- unrealon_sdk/src/cli/commands/integration.py +0 -498
- unrealon_sdk/src/cli/commands/reports.py +0 -43
- unrealon_sdk/src/cli/commands/security.py +0 -36
- unrealon_sdk/src/cli/commands/server.py +0 -483
- unrealon_sdk/src/cli/commands/servers.py +0 -56
- unrealon_sdk/src/cli/commands/tests.py +0 -55
- unrealon_sdk/src/cli/main.py +0 -126
- unrealon_sdk/src/cli/utils/reporter.py +0 -519
- unrealon_sdk/src/clients/openapi.yaml +0 -3347
- unrealon_sdk/src/clients/python_http/__init__.py +0 -3
- unrealon_sdk/src/clients/python_http/api_config.py +0 -228
- unrealon_sdk/src/clients/python_http/models/BaseModel.py +0 -12
- unrealon_sdk/src/clients/python_http/models/BroadcastDeliveryStats.py +0 -33
- unrealon_sdk/src/clients/python_http/models/BroadcastMessage.py +0 -17
- unrealon_sdk/src/clients/python_http/models/BroadcastMessageRequest.py +0 -35
- unrealon_sdk/src/clients/python_http/models/BroadcastPriority.py +0 -10
- unrealon_sdk/src/clients/python_http/models/BroadcastResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/BroadcastResultResponse.py +0 -33
- unrealon_sdk/src/clients/python_http/models/BroadcastTarget.py +0 -11
- unrealon_sdk/src/clients/python_http/models/ConnectionStats.py +0 -27
- unrealon_sdk/src/clients/python_http/models/ConnectionsResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/DeveloperMessageResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ErrorResponse.py +0 -25
- unrealon_sdk/src/clients/python_http/models/HTTPValidationError.py +0 -16
- unrealon_sdk/src/clients/python_http/models/HealthResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/HealthStatus.py +0 -33
- unrealon_sdk/src/clients/python_http/models/LogLevel.py +0 -10
- unrealon_sdk/src/clients/python_http/models/LoggingRequest.py +0 -27
- unrealon_sdk/src/clients/python_http/models/LoggingResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/MaintenanceMode.py +0 -9
- unrealon_sdk/src/clients/python_http/models/MaintenanceModeRequest.py +0 -33
- unrealon_sdk/src/clients/python_http/models/MaintenanceStatusResponse.py +0 -39
- unrealon_sdk/src/clients/python_http/models/ParserCommandRequest.py +0 -25
- unrealon_sdk/src/clients/python_http/models/ParserMessageResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/ParserRegistrationRequest.py +0 -28
- unrealon_sdk/src/clients/python_http/models/ParserRegistrationResponse.py +0 -25
- unrealon_sdk/src/clients/python_http/models/ParserType.py +0 -10
- unrealon_sdk/src/clients/python_http/models/ProxyBlockRequest.py +0 -19
- unrealon_sdk/src/clients/python_http/models/ProxyEndpointResponse.py +0 -20
- unrealon_sdk/src/clients/python_http/models/ProxyListResponse.py +0 -19
- unrealon_sdk/src/clients/python_http/models/ProxyProvider.py +0 -10
- unrealon_sdk/src/clients/python_http/models/ProxyPurchaseRequest.py +0 -25
- unrealon_sdk/src/clients/python_http/models/ProxyResponse.py +0 -47
- unrealon_sdk/src/clients/python_http/models/ProxyRotationRequest.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ProxyStatus.py +0 -10
- unrealon_sdk/src/clients/python_http/models/ProxyUsageRequest.py +0 -19
- unrealon_sdk/src/clients/python_http/models/ProxyUsageStatsResponse.py +0 -26
- unrealon_sdk/src/clients/python_http/models/ServiceRegistrationDto.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ServiceStatsResponse.py +0 -31
- unrealon_sdk/src/clients/python_http/models/SessionStartRequest.py +0 -23
- unrealon_sdk/src/clients/python_http/models/SuccessResponse.py +0 -25
- unrealon_sdk/src/clients/python_http/models/SystemNotificationResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ValidationError.py +0 -18
- unrealon_sdk/src/clients/python_http/models/ValidationErrorResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/WebSocketMetrics.py +0 -21
- unrealon_sdk/src/clients/python_http/models/__init__.py +0 -44
- unrealon_sdk/src/clients/python_http/services/None_service.py +0 -35
- unrealon_sdk/src/clients/python_http/services/ParserManagement_service.py +0 -190
- unrealon_sdk/src/clients/python_http/services/ProxyManagement_service.py +0 -289
- unrealon_sdk/src/clients/python_http/services/SocketLogging_service.py +0 -187
- unrealon_sdk/src/clients/python_http/services/SystemHealth_service.py +0 -119
- unrealon_sdk/src/clients/python_http/services/WebSocketAPI_service.py +0 -198
- unrealon_sdk/src/clients/python_http/services/__init__.py +0 -0
- unrealon_sdk/src/clients/python_http/services/admin_service.py +0 -125
- unrealon_sdk/src/clients/python_http/services/async_None_service.py +0 -35
- unrealon_sdk/src/clients/python_http/services/async_ParserManagement_service.py +0 -190
- unrealon_sdk/src/clients/python_http/services/async_ProxyManagement_service.py +0 -289
- unrealon_sdk/src/clients/python_http/services/async_SocketLogging_service.py +0 -189
- unrealon_sdk/src/clients/python_http/services/async_SystemHealth_service.py +0 -123
- unrealon_sdk/src/clients/python_http/services/async_WebSocketAPI_service.py +0 -200
- unrealon_sdk/src/clients/python_http/services/async_admin_service.py +0 -125
- unrealon_sdk/src/clients/python_websocket/__init__.py +0 -28
- unrealon_sdk/src/clients/python_websocket/client.py +0 -490
- unrealon_sdk/src/clients/python_websocket/events.py +0 -732
- unrealon_sdk/src/clients/python_websocket/example.py +0 -136
- unrealon_sdk/src/clients/python_websocket/types.py +0 -871
- unrealon_sdk/src/core/__init__.py +0 -64
- unrealon_sdk/src/core/client.py +0 -556
- unrealon_sdk/src/core/config.py +0 -465
- unrealon_sdk/src/core/exceptions.py +0 -239
- unrealon_sdk/src/core/metadata.py +0 -191
- unrealon_sdk/src/core/models.py +0 -142
- unrealon_sdk/src/core/types.py +0 -68
- unrealon_sdk/src/dto/__init__.py +0 -268
- unrealon_sdk/src/dto/authentication.py +0 -108
- unrealon_sdk/src/dto/cache.py +0 -208
- unrealon_sdk/src/dto/common.py +0 -19
- unrealon_sdk/src/dto/concurrency.py +0 -393
- unrealon_sdk/src/dto/events.py +0 -108
- unrealon_sdk/src/dto/health.py +0 -339
- unrealon_sdk/src/dto/load_balancing.py +0 -336
- unrealon_sdk/src/dto/logging.py +0 -230
- unrealon_sdk/src/dto/performance.py +0 -165
- unrealon_sdk/src/dto/rate_limiting.py +0 -295
- unrealon_sdk/src/dto/resource_pooling.py +0 -128
- unrealon_sdk/src/dto/structured_logging.py +0 -112
- unrealon_sdk/src/dto/task_scheduling.py +0 -121
- unrealon_sdk/src/dto/websocket.py +0 -55
- unrealon_sdk/src/enterprise/__init__.py +0 -59
- unrealon_sdk/src/enterprise/authentication.py +0 -401
- unrealon_sdk/src/enterprise/cache_manager.py +0 -578
- unrealon_sdk/src/enterprise/error_recovery.py +0 -494
- unrealon_sdk/src/enterprise/event_system.py +0 -549
- unrealon_sdk/src/enterprise/health_monitor.py +0 -747
- unrealon_sdk/src/enterprise/load_balancer.py +0 -964
- unrealon_sdk/src/enterprise/logging/__init__.py +0 -68
- unrealon_sdk/src/enterprise/logging/cleanup.py +0 -156
- unrealon_sdk/src/enterprise/logging/development.py +0 -744
- unrealon_sdk/src/enterprise/logging/service.py +0 -410
- unrealon_sdk/src/enterprise/multithreading_manager.py +0 -853
- unrealon_sdk/src/enterprise/performance_monitor.py +0 -539
- unrealon_sdk/src/enterprise/proxy_manager.py +0 -696
- unrealon_sdk/src/enterprise/rate_limiter.py +0 -652
- unrealon_sdk/src/enterprise/resource_pool.py +0 -763
- unrealon_sdk/src/enterprise/task_scheduler.py +0 -709
- unrealon_sdk/src/internal/__init__.py +0 -10
- unrealon_sdk/src/internal/command_router.py +0 -497
- unrealon_sdk/src/internal/connection_manager.py +0 -397
- unrealon_sdk/src/internal/http_client.py +0 -446
- unrealon_sdk/src/internal/websocket_client.py +0 -420
- unrealon_sdk/src/provider.py +0 -471
- unrealon_sdk/src/utils.py +0 -234
- /unrealon_browser/{src/cli → cli}/__init__.py +0 -0
- /unrealon_browser/{src/cli → cli}/interactive_mode.py +0 -0
- /unrealon_browser/{src/cli → cli}/main.py +0 -0
- /unrealon_browser/{src/core → core}/__init__.py +0 -0
- /unrealon_browser/{src/dto → dto}/__init__.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/config.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/core.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/dataclasses.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/detection.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/enums.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/statistics.py +0 -0
- /unrealon_browser/{src/managers → managers}/__init__.py +0 -0
- /unrealon_browser/{src/managers → managers}/stealth.py +0 -0
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Internal SDK components for UnrealOn SDK v1.0
|
|
3
|
-
|
|
4
|
-
This module contains internal implementation details that are not part
|
|
5
|
-
of the public API. These components handle low-level communication,
|
|
6
|
-
command routing, and connection management.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
# Internal components are not exported in public API
|
|
10
|
-
# They are only used internally by the SDK
|
|
@@ -1,497 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Command routing and handling for UnrealOn SDK v1.0
|
|
3
|
-
|
|
4
|
-
Provides intelligent command routing with:
|
|
5
|
-
- Type-safe command dispatch using Pydantic v2 models
|
|
6
|
-
- Priority handling with configurable strategies
|
|
7
|
-
- Timeout management with automatic cancellation
|
|
8
|
-
- Performance monitoring and metrics collection
|
|
9
|
-
- Concurrent execution control with resource management
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import asyncio
|
|
13
|
-
import logging
|
|
14
|
-
from typing import Dict, Callable, Optional, Awaitable, Any, Union
|
|
15
|
-
from datetime import datetime, timedelta
|
|
16
|
-
from dataclasses import dataclass
|
|
17
|
-
from enum import Enum
|
|
18
|
-
|
|
19
|
-
# Use auto-generated models only - no custom models!
|
|
20
|
-
from unrealon_sdk.src.clients.python_websocket.types import ParserCommandEvent, CommandStatus
|
|
21
|
-
from unrealon_sdk.src.clients.python_http.models import SuccessResponse, ErrorResponse
|
|
22
|
-
|
|
23
|
-
# SDK metadata models
|
|
24
|
-
from unrealon_sdk.src.core.metadata import ExecutionInfo, RouterStatistics
|
|
25
|
-
from unrealon_sdk.src.core.exceptions import CommandError, TimeoutError as SDKTimeoutError
|
|
26
|
-
from unrealon_sdk.src.utils import generate_correlation_id
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class CommandPriority(str, Enum):
|
|
30
|
-
"""Command priority levels for queue ordering."""
|
|
31
|
-
|
|
32
|
-
LOW = "low"
|
|
33
|
-
NORMAL = "normal"
|
|
34
|
-
HIGH = "high"
|
|
35
|
-
URGENT = "urgent"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@dataclass
|
|
39
|
-
class CommandExecution:
|
|
40
|
-
"""Tracks command execution state with comprehensive monitoring."""
|
|
41
|
-
|
|
42
|
-
command: ParserCommandEvent
|
|
43
|
-
handler: Callable
|
|
44
|
-
started_at: datetime
|
|
45
|
-
correlation_id: str
|
|
46
|
-
task: Optional[asyncio.Task] = None
|
|
47
|
-
timeout_task: Optional[asyncio.Task] = None
|
|
48
|
-
priority: CommandPriority = CommandPriority.NORMAL
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def execution_time_ms(self) -> float:
|
|
52
|
-
"""Get current execution time in milliseconds."""
|
|
53
|
-
return (datetime.utcnow() - self.started_at).total_seconds() * 1000
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def is_running(self) -> bool:
|
|
57
|
-
"""Check if command is currently running."""
|
|
58
|
-
return self.task is not None and not self.task.done()
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def is_timed_out(self) -> bool:
|
|
62
|
-
"""Check if command has timed out."""
|
|
63
|
-
return (
|
|
64
|
-
self.timeout_task is not None
|
|
65
|
-
and self.timeout_task.done()
|
|
66
|
-
and not self.timeout_task.cancelled()
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
class CommandRouter:
|
|
71
|
-
"""
|
|
72
|
-
Routes and manages command execution with enterprise-grade capabilities.
|
|
73
|
-
|
|
74
|
-
Features:
|
|
75
|
-
- Priority-based command queuing with multiple strategies
|
|
76
|
-
- Concurrent execution control with resource management
|
|
77
|
-
- Comprehensive timeout handling with cancellation
|
|
78
|
-
- Performance metrics collection and analysis
|
|
79
|
-
- Error correlation and recovery recommendations
|
|
80
|
-
- Circuit breaker pattern for failed handlers
|
|
81
|
-
|
|
82
|
-
Follows Layer 2 requirements from development checklist:
|
|
83
|
-
- Type-safe command dispatch
|
|
84
|
-
- Automatic retry with exponential backoff
|
|
85
|
-
- Resource monitoring and optimization
|
|
86
|
-
- Error recovery and circuit breaker patterns
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
def __init__(self, max_concurrent_commands: int = 10, default_timeout: int = 300):
|
|
90
|
-
"""
|
|
91
|
-
Initialize command router.
|
|
92
|
-
|
|
93
|
-
Args:
|
|
94
|
-
max_concurrent_commands: Maximum concurrent command executions
|
|
95
|
-
default_timeout: Default command timeout in seconds
|
|
96
|
-
"""
|
|
97
|
-
self.logger = logging.getLogger("unrealon_sdk.command_router")
|
|
98
|
-
|
|
99
|
-
# Command handlers registry
|
|
100
|
-
self._handlers: Dict[str, Callable] = {}
|
|
101
|
-
|
|
102
|
-
# Execution tracking
|
|
103
|
-
self._active_executions: Dict[str, CommandExecution] = {}
|
|
104
|
-
self._command_queue: asyncio.PriorityQueue = asyncio.PriorityQueue()
|
|
105
|
-
|
|
106
|
-
# Configuration
|
|
107
|
-
self._max_concurrent_commands = max_concurrent_commands
|
|
108
|
-
self._default_timeout = default_timeout
|
|
109
|
-
|
|
110
|
-
# Statistics and monitoring
|
|
111
|
-
self._total_commands = 0
|
|
112
|
-
self._successful_commands = 0
|
|
113
|
-
self._failed_commands = 0
|
|
114
|
-
self._timeout_commands = 0
|
|
115
|
-
self._cancelled_commands = 0
|
|
116
|
-
|
|
117
|
-
# Performance tracking
|
|
118
|
-
self._total_execution_time = 0.0
|
|
119
|
-
self._min_execution_time = float("inf")
|
|
120
|
-
self._max_execution_time = 0.0
|
|
121
|
-
|
|
122
|
-
# Circuit breaker for handlers
|
|
123
|
-
self._handler_failures: Dict[str, int] = {}
|
|
124
|
-
self._handler_last_failure: Dict[str, datetime] = {}
|
|
125
|
-
self._circuit_breaker_threshold = 5
|
|
126
|
-
self._circuit_breaker_timeout = timedelta(minutes=5)
|
|
127
|
-
|
|
128
|
-
self.logger.debug(
|
|
129
|
-
f"CommandRouter initialized with max_concurrent={max_concurrent_commands}"
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
def register_handler(
|
|
133
|
-
self,
|
|
134
|
-
command_type: str,
|
|
135
|
-
handler: Callable[[ParserCommandEvent], Awaitable[Union[SuccessResponse, ErrorResponse]]],
|
|
136
|
-
) -> None:
|
|
137
|
-
"""
|
|
138
|
-
Register a command handler.
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
command_type: Type of command to handle
|
|
142
|
-
handler: Async function to handle the command
|
|
143
|
-
"""
|
|
144
|
-
self._handlers[command_type] = handler
|
|
145
|
-
|
|
146
|
-
# Reset circuit breaker for this handler
|
|
147
|
-
self._handler_failures[command_type] = 0
|
|
148
|
-
if command_type in self._handler_last_failure:
|
|
149
|
-
del self._handler_last_failure[command_type]
|
|
150
|
-
|
|
151
|
-
self.logger.debug(f"Registered handler for command type: {command_type}")
|
|
152
|
-
|
|
153
|
-
def unregister_handler(self, command_type: str) -> None:
|
|
154
|
-
"""
|
|
155
|
-
Unregister a command handler.
|
|
156
|
-
|
|
157
|
-
Args:
|
|
158
|
-
command_type: Type of command to unregister
|
|
159
|
-
"""
|
|
160
|
-
if command_type in self._handlers:
|
|
161
|
-
del self._handlers[command_type]
|
|
162
|
-
self.logger.debug(f"Unregistered handler for command type: {command_type}")
|
|
163
|
-
|
|
164
|
-
async def route_command(
|
|
165
|
-
self, command: ParserCommandEvent
|
|
166
|
-
) -> Union[SuccessResponse, ErrorResponse]:
|
|
167
|
-
"""
|
|
168
|
-
Route and execute a command with comprehensive error handling.
|
|
169
|
-
|
|
170
|
-
Args:
|
|
171
|
-
command: Command to execute
|
|
172
|
-
|
|
173
|
-
Returns:
|
|
174
|
-
Command response
|
|
175
|
-
|
|
176
|
-
Raises:
|
|
177
|
-
CommandError: If no handler exists for command type or execution fails
|
|
178
|
-
"""
|
|
179
|
-
self._total_commands += 1
|
|
180
|
-
start_time = datetime.utcnow()
|
|
181
|
-
correlation_id = generate_correlation_id()
|
|
182
|
-
|
|
183
|
-
self.logger.info(
|
|
184
|
-
f"Routing command {command.command_id} of type {command.command_type}",
|
|
185
|
-
extra={"correlation_id": correlation_id},
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
try:
|
|
189
|
-
# Validate command and handler
|
|
190
|
-
await self._validate_command(command)
|
|
191
|
-
|
|
192
|
-
# Check circuit breaker for handler
|
|
193
|
-
if self._is_circuit_breaker_open(command.command_type):
|
|
194
|
-
raise CommandError(
|
|
195
|
-
f"Circuit breaker open for command type: {command.command_type}",
|
|
196
|
-
error_code="CIRCUIT_BREAKER_OPEN",
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
# Check concurrent execution limit
|
|
200
|
-
if len(self._active_executions) >= self._max_concurrent_commands:
|
|
201
|
-
raise CommandError(
|
|
202
|
-
f"Maximum concurrent commands limit reached ({self._max_concurrent_commands})",
|
|
203
|
-
error_code="CONCURRENT_LIMIT_EXCEEDED",
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
# Execute command
|
|
207
|
-
response = await self._execute_command(command, correlation_id, start_time)
|
|
208
|
-
|
|
209
|
-
# Update statistics for successful execution
|
|
210
|
-
self._update_success_statistics(start_time)
|
|
211
|
-
|
|
212
|
-
return response
|
|
213
|
-
|
|
214
|
-
except Exception as e:
|
|
215
|
-
# Update statistics for failed execution
|
|
216
|
-
self._update_failure_statistics(command.command_type, start_time)
|
|
217
|
-
|
|
218
|
-
# Create error response
|
|
219
|
-
error_response = self._create_error_response(command, e, correlation_id, start_time)
|
|
220
|
-
|
|
221
|
-
self.logger.error(
|
|
222
|
-
f"Command {command.command_id} failed: {e}",
|
|
223
|
-
extra={"correlation_id": correlation_id},
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
return error_response
|
|
227
|
-
|
|
228
|
-
async def _validate_command(self, command: ParserCommandEvent) -> None:
|
|
229
|
-
"""Validate command before execution."""
|
|
230
|
-
if command.command_type not in self._handlers:
|
|
231
|
-
raise CommandError(
|
|
232
|
-
f"No handler registered for command type: {command.command_type}",
|
|
233
|
-
error_code="HANDLER_NOT_FOUND",
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
# Validate command structure using Pydantic (already validated during parsing)
|
|
237
|
-
# Additional business logic validation can be added here
|
|
238
|
-
|
|
239
|
-
def _is_circuit_breaker_open(self, command_type: str) -> bool:
|
|
240
|
-
"""Check if circuit breaker is open for a command type."""
|
|
241
|
-
failure_count = self._handler_failures.get(command_type, 0)
|
|
242
|
-
last_failure = self._handler_last_failure.get(command_type)
|
|
243
|
-
|
|
244
|
-
if failure_count < self._circuit_breaker_threshold:
|
|
245
|
-
return False
|
|
246
|
-
|
|
247
|
-
if last_failure is None:
|
|
248
|
-
return False
|
|
249
|
-
|
|
250
|
-
# Check if timeout has passed
|
|
251
|
-
if datetime.utcnow() - last_failure > self._circuit_breaker_timeout:
|
|
252
|
-
# Reset circuit breaker
|
|
253
|
-
self._handler_failures[command_type] = 0
|
|
254
|
-
del self._handler_last_failure[command_type]
|
|
255
|
-
return False
|
|
256
|
-
|
|
257
|
-
return True
|
|
258
|
-
|
|
259
|
-
async def _execute_command(
|
|
260
|
-
self, command: ParserCommandEvent, correlation_id: str, start_time: datetime
|
|
261
|
-
) -> Union[SuccessResponse, ErrorResponse]:
|
|
262
|
-
"""Execute command with timeout and cancellation support."""
|
|
263
|
-
|
|
264
|
-
handler = self._handlers[command.command_type]
|
|
265
|
-
execution = CommandExecution(
|
|
266
|
-
command=command, handler=handler, started_at=start_time, correlation_id=correlation_id
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
# Add to active executions
|
|
270
|
-
self._active_executions[command.command_id] = execution
|
|
271
|
-
|
|
272
|
-
try:
|
|
273
|
-
# Create execution task
|
|
274
|
-
execution.task = asyncio.create_task(handler(command))
|
|
275
|
-
|
|
276
|
-
# Create timeout task
|
|
277
|
-
timeout_seconds = command.timeout_seconds or self._default_timeout
|
|
278
|
-
execution.timeout_task = asyncio.create_task(
|
|
279
|
-
self._handle_timeout(command, timeout_seconds)
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
# Wait for either completion or timeout
|
|
283
|
-
done, pending = await asyncio.wait(
|
|
284
|
-
[execution.task, execution.timeout_task], return_when=asyncio.FIRST_COMPLETED
|
|
285
|
-
)
|
|
286
|
-
|
|
287
|
-
# Cancel pending tasks
|
|
288
|
-
for task in pending:
|
|
289
|
-
task.cancel()
|
|
290
|
-
try:
|
|
291
|
-
await task
|
|
292
|
-
except asyncio.CancelledError:
|
|
293
|
-
pass
|
|
294
|
-
|
|
295
|
-
# Check if command completed or timed out
|
|
296
|
-
if execution.task in done:
|
|
297
|
-
# Command completed successfully
|
|
298
|
-
result_data = await execution.task
|
|
299
|
-
execution_time = execution.execution_time_ms
|
|
300
|
-
|
|
301
|
-
self._successful_commands += 1
|
|
302
|
-
|
|
303
|
-
response = SuccessResponse(
|
|
304
|
-
success=True,
|
|
305
|
-
message="Command completed successfully",
|
|
306
|
-
data=result_data,
|
|
307
|
-
timestamp=datetime.utcnow().isoformat(),
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
self.logger.info(
|
|
311
|
-
f"Command {command.command_id} completed in {execution_time:.2f}ms",
|
|
312
|
-
extra={"correlation_id": correlation_id},
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
return response
|
|
316
|
-
|
|
317
|
-
else:
|
|
318
|
-
# Command timed out
|
|
319
|
-
execution_time = execution.execution_time_ms
|
|
320
|
-
self._timeout_commands += 1
|
|
321
|
-
|
|
322
|
-
response = ErrorResponse(
|
|
323
|
-
success=False,
|
|
324
|
-
message=f"Command timed out after {timeout_seconds} seconds",
|
|
325
|
-
error_code="COMMAND_TIMEOUT",
|
|
326
|
-
timestamp=datetime.utcnow().isoformat(),
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
self.logger.warning(
|
|
330
|
-
f"Command {command.command_id} timed out after {execution_time:.2f}ms",
|
|
331
|
-
extra={"correlation_id": correlation_id},
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
return response
|
|
335
|
-
|
|
336
|
-
finally:
|
|
337
|
-
# Cleanup execution tracking
|
|
338
|
-
if command.command_id in self._active_executions:
|
|
339
|
-
del self._active_executions[command.command_id]
|
|
340
|
-
|
|
341
|
-
async def _handle_timeout(self, command: ParserCommandEvent, timeout_seconds: int) -> None:
|
|
342
|
-
"""Handle command timeout."""
|
|
343
|
-
await asyncio.sleep(timeout_seconds)
|
|
344
|
-
self.logger.warning(
|
|
345
|
-
f"Command {command.command_id} exceeded timeout of {timeout_seconds} seconds"
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
def _update_success_statistics(self, start_time: datetime) -> None:
|
|
349
|
-
"""Update statistics for successful command execution."""
|
|
350
|
-
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
|
351
|
-
|
|
352
|
-
self._total_execution_time += execution_time
|
|
353
|
-
self._min_execution_time = min(self._min_execution_time, execution_time)
|
|
354
|
-
self._max_execution_time = max(self._max_execution_time, execution_time)
|
|
355
|
-
|
|
356
|
-
def _update_failure_statistics(self, command_type: str, start_time: datetime) -> None:
|
|
357
|
-
"""Update statistics for failed command execution."""
|
|
358
|
-
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
|
359
|
-
|
|
360
|
-
self._failed_commands += 1
|
|
361
|
-
self._total_execution_time += execution_time
|
|
362
|
-
|
|
363
|
-
# Update circuit breaker
|
|
364
|
-
self._handler_failures[command_type] = self._handler_failures.get(command_type, 0) + 1
|
|
365
|
-
self._handler_last_failure[command_type] = datetime.utcnow()
|
|
366
|
-
|
|
367
|
-
def _create_error_response(
|
|
368
|
-
self,
|
|
369
|
-
command: ParserCommandEvent,
|
|
370
|
-
error: Exception,
|
|
371
|
-
correlation_id: str,
|
|
372
|
-
start_time: datetime,
|
|
373
|
-
) -> ErrorResponse:
|
|
374
|
-
"""Create structured error response."""
|
|
375
|
-
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
|
376
|
-
|
|
377
|
-
# Determine error details
|
|
378
|
-
if isinstance(error, CommandError):
|
|
379
|
-
error_message = str(error)
|
|
380
|
-
error_code = getattr(error, "error_code", "COMMAND_ERROR")
|
|
381
|
-
elif isinstance(error, TimeoutError):
|
|
382
|
-
error_message = str(error)
|
|
383
|
-
error_code = "TIMEOUT_ERROR"
|
|
384
|
-
else:
|
|
385
|
-
error_message = f"Unexpected error: {str(error)}"
|
|
386
|
-
error_code = "INTERNAL_ERROR"
|
|
387
|
-
|
|
388
|
-
return ErrorResponse(
|
|
389
|
-
success=False,
|
|
390
|
-
message=error_message,
|
|
391
|
-
error_code=error_code,
|
|
392
|
-
timestamp=datetime.utcnow().isoformat(),
|
|
393
|
-
)
|
|
394
|
-
|
|
395
|
-
def get_registered_handlers(self) -> Dict[str, str]:
|
|
396
|
-
"""Get information about registered handlers."""
|
|
397
|
-
return {
|
|
398
|
-
cmd_type: handler.__name__ if hasattr(handler, "__name__") else str(handler)
|
|
399
|
-
for cmd_type, handler in self._handlers.items()
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
def get_active_executions(self) -> Dict[str, ExecutionInfo]:
|
|
403
|
-
"""Get information about currently executing commands."""
|
|
404
|
-
return {
|
|
405
|
-
cmd_id: ExecutionInfo(
|
|
406
|
-
command_id=cmd_id,
|
|
407
|
-
command_type=execution.command.command_type,
|
|
408
|
-
status=(
|
|
409
|
-
"running"
|
|
410
|
-
if execution.is_running
|
|
411
|
-
else ("timeout" if execution.is_timed_out else "completed")
|
|
412
|
-
),
|
|
413
|
-
start_time=execution.started_at,
|
|
414
|
-
duration_ms=execution.execution_time_ms,
|
|
415
|
-
)
|
|
416
|
-
for cmd_id, execution in self._active_executions.items()
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
def get_statistics(self) -> RouterStatistics:
|
|
420
|
-
"""Get comprehensive command execution statistics."""
|
|
421
|
-
avg_execution_time = (
|
|
422
|
-
self._total_execution_time / self._total_commands if self._total_commands > 0 else 0
|
|
423
|
-
)
|
|
424
|
-
|
|
425
|
-
success_rate = (
|
|
426
|
-
self._successful_commands / self._total_commands * 100
|
|
427
|
-
if self._total_commands > 0
|
|
428
|
-
else 0
|
|
429
|
-
)
|
|
430
|
-
|
|
431
|
-
return RouterStatistics(
|
|
432
|
-
total_commands=self._total_commands,
|
|
433
|
-
successful_commands=self._successful_commands,
|
|
434
|
-
failed_commands=self._failed_commands,
|
|
435
|
-
average_execution_time_ms=avg_execution_time,
|
|
436
|
-
active_executions=len(self._active_executions),
|
|
437
|
-
success_rate=success_rate,
|
|
438
|
-
)
|
|
439
|
-
|
|
440
|
-
async def cancel_command(self, command_id: str) -> bool:
|
|
441
|
-
"""
|
|
442
|
-
Cancel an active command execution.
|
|
443
|
-
|
|
444
|
-
Args:
|
|
445
|
-
command_id: ID of command to cancel
|
|
446
|
-
|
|
447
|
-
Returns:
|
|
448
|
-
True if command was cancelled, False if not found
|
|
449
|
-
"""
|
|
450
|
-
if command_id not in self._active_executions:
|
|
451
|
-
return False
|
|
452
|
-
|
|
453
|
-
execution = self._active_executions[command_id]
|
|
454
|
-
|
|
455
|
-
# Cancel tasks
|
|
456
|
-
if execution.task and not execution.task.done():
|
|
457
|
-
execution.task.cancel()
|
|
458
|
-
|
|
459
|
-
if execution.timeout_task and not execution.timeout_task.done():
|
|
460
|
-
execution.timeout_task.cancel()
|
|
461
|
-
|
|
462
|
-
# Update statistics
|
|
463
|
-
self._cancelled_commands += 1
|
|
464
|
-
|
|
465
|
-
# Remove from tracking
|
|
466
|
-
del self._active_executions[command_id]
|
|
467
|
-
|
|
468
|
-
self.logger.info(f"Cancelled command {command_id}")
|
|
469
|
-
return True
|
|
470
|
-
|
|
471
|
-
async def shutdown(self) -> None:
|
|
472
|
-
"""Shutdown the command router and cancel all active executions."""
|
|
473
|
-
self.logger.info("Shutting down command router...")
|
|
474
|
-
|
|
475
|
-
# Cancel all active executions
|
|
476
|
-
active_commands = list(self._active_executions.keys())
|
|
477
|
-
for command_id in active_commands:
|
|
478
|
-
await self.cancel_command(command_id)
|
|
479
|
-
|
|
480
|
-
self.logger.info(
|
|
481
|
-
f"Command router shutdown complete. Cancelled {len(active_commands)} commands"
|
|
482
|
-
)
|
|
483
|
-
|
|
484
|
-
def reset_statistics(self) -> None:
|
|
485
|
-
"""Reset all statistics (useful for testing)."""
|
|
486
|
-
self._total_commands = 0
|
|
487
|
-
self._successful_commands = 0
|
|
488
|
-
self._failed_commands = 0
|
|
489
|
-
self._timeout_commands = 0
|
|
490
|
-
self._cancelled_commands = 0
|
|
491
|
-
self._total_execution_time = 0.0
|
|
492
|
-
self._min_execution_time = float("inf")
|
|
493
|
-
self._max_execution_time = 0.0
|
|
494
|
-
self._handler_failures.clear()
|
|
495
|
-
self._handler_last_failure.clear()
|
|
496
|
-
|
|
497
|
-
self.logger.debug("Command router statistics reset")
|