unrealon 2.0.7__tar.gz → 2.0.9__tar.gz
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-2.0.7/unrealon.egg-info → unrealon-2.0.9}/PKG-INFO +1 -1
- {unrealon-2.0.7 → unrealon-2.0.9}/pyproject.toml +1 -1
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/core/browser_manager.py +6 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/__init__.py +2 -0
- unrealon-2.0.9/unrealon-browser/src/unrealon_browser/managers/script_manager.py +314 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/manager.pyc +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/config/urls.py +2 -1
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/enums/__init__.py +10 -0
- unrealon-2.0.9/unrealon-core/src/unrealon_core/enums/events.py +98 -0
- unrealon-2.0.9/unrealon-core/src/unrealon_core/enums/jobs.py +32 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/enums/types.py +1 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/__init__.py +9 -0
- unrealon-2.0.9/unrealon-core/src/unrealon_core/models/authentication.py +24 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/browser.py +21 -1
- {unrealon-2.0.7 → unrealon-2.0.9/unrealon.egg-info}/PKG-INFO +1 -1
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/SOURCES.txt +4 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/LICENSE +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/MANIFEST.in +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/README.md +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/setup.cfg +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/README.md +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/browser_cli.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/cookies_cli.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/interactive_mode.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/main.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/core/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/bot_detection.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/config.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/core.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/dataclasses.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/detection.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/enums.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/statistics.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/captcha.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/cookies.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/logger_bridge.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/profile.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.pyc +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/playwright_stealth.pyc +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.pyc +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/undetected_chrome.pyc +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/config/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/config/environment.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/enums/status.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/error_context.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/recovery.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/retry.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/base.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/communication.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/driver.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/proxy.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/task.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/validation.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/arq_context.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/arq_responses.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/base.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/bridge_stats.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/communication.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/connection_stats.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/driver.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/driver_details.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/logging.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/task.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/typed_responses.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/base.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/broadcast.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/config.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/driver.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/errors.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/logging.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/proxy.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/tasks.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/utils.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket_session.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/alerts.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/dashboard.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/health_check.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/metrics.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/utils/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/utils/time.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/version.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/base.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/config.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/event_manager.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/protocols.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/registry.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/retry.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/schedule.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/task.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/timing.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/communication/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/communication/session.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/communication/websocket_client.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/config.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/driver.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/factory/manager_factory.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/initialization.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/serialization.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/base.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/cache.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/http.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/logger.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/proxy.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/registry.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/threading.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/managers/update.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/utils/__init__.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/utils/time.py +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/dependency_links.txt +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/entry_points.txt +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/requires.txt +0 -0
- {unrealon-2.0.7 → unrealon-2.0.9}/unrealon.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "unrealon"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.9"
|
|
8
8
|
description = "Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "UnrealOn Team", email = "team@unrealon.com"}
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/core/browser_manager.py
RENAMED
|
@@ -30,6 +30,7 @@ from unrealon_browser.managers import (
|
|
|
30
30
|
CaptchaDetector,
|
|
31
31
|
create_browser_logger_bridge,
|
|
32
32
|
PageWaitManager,
|
|
33
|
+
ScriptManager,
|
|
33
34
|
)
|
|
34
35
|
|
|
35
36
|
|
|
@@ -66,6 +67,7 @@ class BrowserManager:
|
|
|
66
67
|
self.cookie_manager = None
|
|
67
68
|
self.captcha_manager = CaptchaDetector()
|
|
68
69
|
self.page_wait = PageWaitManager(None, self.logger_bridge)
|
|
70
|
+
self.script_manager = ScriptManager(None, self.logger_bridge)
|
|
69
71
|
|
|
70
72
|
# Signal handlers for graceful shutdown
|
|
71
73
|
self._setup_signal_handlers()
|
|
@@ -231,6 +233,9 @@ class BrowserManager:
|
|
|
231
233
|
|
|
232
234
|
# Update page wait manager with new page
|
|
233
235
|
self.page_wait.update_page(self._page)
|
|
236
|
+
|
|
237
|
+
# Update script manager with new page
|
|
238
|
+
self.script_manager.update_page(self._page)
|
|
234
239
|
|
|
235
240
|
# 🔥 STEALTH ALWAYS APPLIED TO EVERY PAGE!
|
|
236
241
|
stealth_success = await self.stealth_manager.apply_stealth(self._page)
|
|
@@ -644,6 +649,7 @@ class BrowserManager:
|
|
|
644
649
|
finally:
|
|
645
650
|
self._page = None
|
|
646
651
|
self.page_wait.update_page(None)
|
|
652
|
+
self.script_manager.update_page(None)
|
|
647
653
|
|
|
648
654
|
# Close context with safety checks
|
|
649
655
|
if self._context:
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/__init__.py
RENAMED
|
@@ -8,6 +8,7 @@ from .logger_bridge import BrowserLoggerBridge, create_browser_logger_bridge
|
|
|
8
8
|
from .cookies import CookieManager
|
|
9
9
|
from .captcha import CaptchaDetector
|
|
10
10
|
from .page_wait_manager import PageWaitManager
|
|
11
|
+
from .script_manager import ScriptManager
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
@@ -18,4 +19,5 @@ __all__ = [
|
|
|
18
19
|
"CookieManager",
|
|
19
20
|
"CaptchaDetector",
|
|
20
21
|
"PageWaitManager",
|
|
22
|
+
"ScriptManager",
|
|
21
23
|
]
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Script Manager - JavaScript execution and evaluation manager
|
|
3
|
+
Layer 2.5: JavaScript Integration - Handles script execution, API calls, and result processing
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import json
|
|
8
|
+
from typing import Any, Dict, Optional, Union, List
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from playwright.async_api import Page
|
|
11
|
+
|
|
12
|
+
from .logger_bridge import BrowserLoggerBridge as LoggingBridge
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ScriptManager:
|
|
16
|
+
"""Manager for JavaScript execution and evaluation"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, page: Optional[Page], logger_bridge: LoggingBridge):
|
|
19
|
+
self._page = page
|
|
20
|
+
self.logger_bridge = logger_bridge
|
|
21
|
+
|
|
22
|
+
# Statistics
|
|
23
|
+
self._scripts_executed = 0
|
|
24
|
+
self._scripts_successful = 0
|
|
25
|
+
self._scripts_failed = 0
|
|
26
|
+
self._api_calls_made = 0
|
|
27
|
+
self._execution_history: List[Dict[str, Any]] = []
|
|
28
|
+
|
|
29
|
+
def update_page(self, page: Optional[Page]):
|
|
30
|
+
"""Update the page reference"""
|
|
31
|
+
self._page = page
|
|
32
|
+
|
|
33
|
+
async def execute_script(self, script: str, timeout: int = 30000) -> Any:
|
|
34
|
+
"""
|
|
35
|
+
Execute JavaScript code and return result
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
script: JavaScript code to execute
|
|
39
|
+
timeout: Timeout in milliseconds
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Script execution result
|
|
43
|
+
"""
|
|
44
|
+
if not self._page:
|
|
45
|
+
raise RuntimeError("No page available for script execution")
|
|
46
|
+
|
|
47
|
+
start_time = datetime.now()
|
|
48
|
+
self._scripts_executed += 1
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
self.logger_bridge.log_info(f"🔧 Executing JavaScript (timeout: {timeout}ms)")
|
|
52
|
+
self.logger_bridge.log_debug(f"Script preview: {script[:100]}...")
|
|
53
|
+
|
|
54
|
+
# Execute script with timeout
|
|
55
|
+
result = await asyncio.wait_for(
|
|
56
|
+
self._page.evaluate(script),
|
|
57
|
+
timeout=timeout / 1000
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
duration_ms = (datetime.now() - start_time).total_seconds() * 1000
|
|
61
|
+
self._scripts_successful += 1
|
|
62
|
+
|
|
63
|
+
# Log execution details
|
|
64
|
+
execution_record = {
|
|
65
|
+
"timestamp": start_time.isoformat(),
|
|
66
|
+
"duration_ms": duration_ms,
|
|
67
|
+
"success": True,
|
|
68
|
+
"result_type": type(result).__name__,
|
|
69
|
+
"script_length": len(script),
|
|
70
|
+
}
|
|
71
|
+
self._execution_history.append(execution_record)
|
|
72
|
+
|
|
73
|
+
self.logger_bridge.log_info(f"✅ Script executed successfully ({duration_ms:.1f}ms)")
|
|
74
|
+
self.logger_bridge.log_debug(f"Result type: {type(result).__name__}")
|
|
75
|
+
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
except asyncio.TimeoutError:
|
|
79
|
+
duration_ms = (datetime.now() - start_time).total_seconds() * 1000
|
|
80
|
+
self._scripts_failed += 1
|
|
81
|
+
|
|
82
|
+
execution_record = {
|
|
83
|
+
"timestamp": start_time.isoformat(),
|
|
84
|
+
"duration_ms": duration_ms,
|
|
85
|
+
"success": False,
|
|
86
|
+
"error": "Timeout",
|
|
87
|
+
"script_length": len(script),
|
|
88
|
+
}
|
|
89
|
+
self._execution_history.append(execution_record)
|
|
90
|
+
|
|
91
|
+
self.logger_bridge.log_error(f"⏰ Script execution timeout ({timeout}ms)")
|
|
92
|
+
raise
|
|
93
|
+
|
|
94
|
+
except Exception as e:
|
|
95
|
+
duration_ms = (datetime.now() - start_time).total_seconds() * 1000
|
|
96
|
+
self._scripts_failed += 1
|
|
97
|
+
|
|
98
|
+
execution_record = {
|
|
99
|
+
"timestamp": start_time.isoformat(),
|
|
100
|
+
"duration_ms": duration_ms,
|
|
101
|
+
"success": False,
|
|
102
|
+
"error": str(e),
|
|
103
|
+
"script_length": len(script),
|
|
104
|
+
}
|
|
105
|
+
self._execution_history.append(execution_record)
|
|
106
|
+
|
|
107
|
+
self.logger_bridge.log_error(f"❌ Script execution failed: {e}")
|
|
108
|
+
raise
|
|
109
|
+
|
|
110
|
+
async def execute_api_call(self, api_url: str, headers: Dict[str, str], method: str = "GET", timeout: int = 30000) -> Dict[str, Any]:
|
|
111
|
+
"""
|
|
112
|
+
Execute API call via JavaScript fetch
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
api_url: API endpoint URL
|
|
116
|
+
headers: HTTP headers
|
|
117
|
+
method: HTTP method
|
|
118
|
+
timeout: Timeout in milliseconds
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
API response data
|
|
122
|
+
"""
|
|
123
|
+
self._api_calls_made += 1
|
|
124
|
+
|
|
125
|
+
# Build fetch script
|
|
126
|
+
headers_json = json.dumps(headers)
|
|
127
|
+
|
|
128
|
+
script = f"""
|
|
129
|
+
(async function() {{
|
|
130
|
+
try {{
|
|
131
|
+
const response = await fetch('{api_url}', {{
|
|
132
|
+
method: '{method}',
|
|
133
|
+
headers: {headers_json}
|
|
134
|
+
}});
|
|
135
|
+
|
|
136
|
+
if (!response.ok) {{
|
|
137
|
+
throw new Error('HTTP error! status: ' + response.status);
|
|
138
|
+
}}
|
|
139
|
+
|
|
140
|
+
const data = await response.json();
|
|
141
|
+
return data;
|
|
142
|
+
}} catch (error) {{
|
|
143
|
+
return {{ error: error.message }};
|
|
144
|
+
}}
|
|
145
|
+
}})()
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
self.logger_bridge.log_info(f"🌐 Making API call: {method} {api_url}")
|
|
149
|
+
|
|
150
|
+
result = await self.execute_script(script, timeout)
|
|
151
|
+
|
|
152
|
+
if isinstance(result, dict) and 'error' in result:
|
|
153
|
+
self.logger_bridge.log_error(f"❌ API call failed: {result['error']}")
|
|
154
|
+
else:
|
|
155
|
+
self.logger_bridge.log_info(f"✅ API call successful")
|
|
156
|
+
|
|
157
|
+
return result
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
async def wait_for_element(self, selector: str, timeout: int = 10000) -> bool:
|
|
161
|
+
"""
|
|
162
|
+
Wait for element using JavaScript
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
selector: CSS selector
|
|
166
|
+
timeout: Timeout in milliseconds
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
True if element found
|
|
170
|
+
"""
|
|
171
|
+
script = f"""
|
|
172
|
+
(function() {{
|
|
173
|
+
return new Promise((resolve) => {{
|
|
174
|
+
const element = document.querySelector('{selector}');
|
|
175
|
+
if (element) {{
|
|
176
|
+
resolve(true);
|
|
177
|
+
return;
|
|
178
|
+
}}
|
|
179
|
+
|
|
180
|
+
const observer = new MutationObserver(() => {{
|
|
181
|
+
const element = document.querySelector('{selector}');
|
|
182
|
+
if (element) {{
|
|
183
|
+
observer.disconnect();
|
|
184
|
+
resolve(true);
|
|
185
|
+
}}
|
|
186
|
+
}});
|
|
187
|
+
|
|
188
|
+
observer.observe(document.body, {{
|
|
189
|
+
childList: true,
|
|
190
|
+
subtree: true
|
|
191
|
+
}});
|
|
192
|
+
|
|
193
|
+
setTimeout(() => {{
|
|
194
|
+
observer.disconnect();
|
|
195
|
+
resolve(false);
|
|
196
|
+
}}, {timeout});
|
|
197
|
+
}});
|
|
198
|
+
}})()
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
self.logger_bridge.log_info(f"🎯 Waiting for element: {selector}")
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
result = await self.execute_script(script, timeout + 1000)
|
|
205
|
+
if result:
|
|
206
|
+
self.logger_bridge.log_info(f"✅ Element found: {selector}")
|
|
207
|
+
else:
|
|
208
|
+
self.logger_bridge.log_warning(f"⏰ Element timeout: {selector}")
|
|
209
|
+
return result
|
|
210
|
+
except Exception as e:
|
|
211
|
+
self.logger_bridge.log_error(f"❌ Element wait failed: {selector} - {e}")
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
async def inject_helper_functions(self) -> bool:
|
|
215
|
+
"""
|
|
216
|
+
Inject helper JavaScript functions into page
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
True if injection successful
|
|
220
|
+
"""
|
|
221
|
+
helper_script = """
|
|
222
|
+
window.unrealonHelpers = {
|
|
223
|
+
// Wait for element with promise
|
|
224
|
+
waitForElement: function(selector, timeout = 10000) {
|
|
225
|
+
return new Promise((resolve) => {
|
|
226
|
+
const element = document.querySelector(selector);
|
|
227
|
+
if (element) {
|
|
228
|
+
resolve(element);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const observer = new MutationObserver(() => {
|
|
233
|
+
const element = document.querySelector(selector);
|
|
234
|
+
if (element) {
|
|
235
|
+
observer.disconnect();
|
|
236
|
+
resolve(element);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
observer.observe(document.body, {
|
|
241
|
+
childList: true,
|
|
242
|
+
subtree: true
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
setTimeout(() => {
|
|
246
|
+
observer.disconnect();
|
|
247
|
+
resolve(null);
|
|
248
|
+
}, timeout);
|
|
249
|
+
});
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
// Get page info
|
|
253
|
+
getPageInfo: function() {
|
|
254
|
+
return {
|
|
255
|
+
url: window.location.href,
|
|
256
|
+
title: document.title,
|
|
257
|
+
readyState: document.readyState,
|
|
258
|
+
timestamp: new Date().toISOString()
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
// Check if SPA loaded
|
|
263
|
+
isSPAReady: function() {
|
|
264
|
+
return document.readyState === 'complete' &&
|
|
265
|
+
document.querySelector('body').children.length > 0;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
console.log('🔧 UnrealOn helper functions injected');
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
await self.execute_script(helper_script)
|
|
274
|
+
self.logger_bridge.log_info("🔧 Helper functions injected successfully")
|
|
275
|
+
return True
|
|
276
|
+
except Exception as e:
|
|
277
|
+
self.logger_bridge.log_error(f"❌ Failed to inject helper functions: {e}")
|
|
278
|
+
return False
|
|
279
|
+
|
|
280
|
+
def get_statistics(self) -> Dict[str, Any]:
|
|
281
|
+
"""Get script execution statistics"""
|
|
282
|
+
success_rate = (self._scripts_successful / self._scripts_executed * 100) if self._scripts_executed > 0 else 0
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
"scripts_executed": self._scripts_executed,
|
|
286
|
+
"scripts_successful": self._scripts_successful,
|
|
287
|
+
"scripts_failed": self._scripts_failed,
|
|
288
|
+
"success_rate": success_rate,
|
|
289
|
+
"api_calls_made": self._api_calls_made,
|
|
290
|
+
"execution_history_count": len(self._execution_history),
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
def print_statistics(self) -> None:
|
|
294
|
+
"""Print script execution statistics"""
|
|
295
|
+
stats = self.get_statistics()
|
|
296
|
+
|
|
297
|
+
self.logger_bridge.log_info("\n🔧 Script Manager Statistics:")
|
|
298
|
+
self.logger_bridge.log_info(f" Scripts executed: {stats['scripts_executed']}")
|
|
299
|
+
self.logger_bridge.log_info(f" Successful: {stats['scripts_successful']}")
|
|
300
|
+
self.logger_bridge.log_info(f" Failed: {stats['scripts_failed']}")
|
|
301
|
+
self.logger_bridge.log_info(f" Success rate: {stats['success_rate']:.1f}%")
|
|
302
|
+
self.logger_bridge.log_info(f" API calls made: {stats['api_calls_made']}")
|
|
303
|
+
|
|
304
|
+
# Show recent executions
|
|
305
|
+
if self._execution_history:
|
|
306
|
+
self.logger_bridge.log_info(" Recent executions:")
|
|
307
|
+
for execution in self._execution_history[-3:]: # Show last 3
|
|
308
|
+
status = "✅" if execution["success"] else "❌"
|
|
309
|
+
self.logger_bridge.log_info(f" {status} {execution['duration_ms']:.1f}ms")
|
|
310
|
+
|
|
311
|
+
def clear_history(self) -> None:
|
|
312
|
+
"""Clear execution history"""
|
|
313
|
+
self._execution_history.clear()
|
|
314
|
+
self.logger_bridge.log_info("🧹 Cleared script execution history")
|
|
Binary file
|
|
@@ -24,6 +24,7 @@ class URLConfig(BaseModel):
|
|
|
24
24
|
|
|
25
25
|
# Cloud platform URLs
|
|
26
26
|
cloud_base_url: str = Field(
|
|
27
|
+
default="https://cloud.unrealon.com",
|
|
27
28
|
description="Base URL for UnrealOn Cloud platform"
|
|
28
29
|
)
|
|
29
30
|
|
|
@@ -41,7 +42,7 @@ class URLConfig(BaseModel):
|
|
|
41
42
|
if environment == Environment.PRODUCTION:
|
|
42
43
|
return cls(
|
|
43
44
|
# scanner_url="https://cloud.unrealon.com/scanner",
|
|
44
|
-
cloud_base_url="https://cloud.unrealon.com",
|
|
45
|
+
# cloud_base_url="https://cloud.unrealon.com",
|
|
45
46
|
api_base_url="https://api.unrealon.com"
|
|
46
47
|
)
|
|
47
48
|
# elif environment == Environment.TESTING:
|
|
@@ -9,6 +9,8 @@ Phase 1: Foundation enums with strict validation
|
|
|
9
9
|
|
|
10
10
|
from .status import DriverStatus, TaskStatus, ProxyStatus, LogLevel
|
|
11
11
|
from .types import MessageType, ProxyType, TaskPriority
|
|
12
|
+
from .events import EventType, SystemEventType, RedisEventType
|
|
13
|
+
from .jobs import ARQJobName
|
|
12
14
|
|
|
13
15
|
__all__ = [
|
|
14
16
|
# Status enums
|
|
@@ -21,4 +23,12 @@ __all__ = [
|
|
|
21
23
|
"MessageType",
|
|
22
24
|
"ProxyType",
|
|
23
25
|
"TaskPriority",
|
|
26
|
+
|
|
27
|
+
# Event enums
|
|
28
|
+
"EventType",
|
|
29
|
+
"SystemEventType",
|
|
30
|
+
"RedisEventType",
|
|
31
|
+
|
|
32
|
+
# Job enums
|
|
33
|
+
"ARQJobName",
|
|
24
34
|
]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Event type enums for UnrealOn system.
|
|
3
|
+
|
|
4
|
+
Centralized event type definitions used across all services.
|
|
5
|
+
"""
|
|
6
|
+
from enum import Enum
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EventType(str, Enum):
|
|
10
|
+
"""
|
|
11
|
+
Event types used in Redis PubSub and system events.
|
|
12
|
+
|
|
13
|
+
These events are used for communication between services:
|
|
14
|
+
- RPC server publishes events
|
|
15
|
+
- Django consumes events via Redis PubSub
|
|
16
|
+
- System events are stored in database
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
# Driver lifecycle events
|
|
20
|
+
DRIVER_REGISTER = "driver_register"
|
|
21
|
+
DRIVER_DISCONNECT = "driver_disconnect"
|
|
22
|
+
|
|
23
|
+
# Parser events (Django-specific naming)
|
|
24
|
+
PARSER_REGISTERED = "parser_registered"
|
|
25
|
+
PARSER_HEARTBEAT = "parser_heartbeat"
|
|
26
|
+
PARSER_DISCONNECTED = "parser_disconnected"
|
|
27
|
+
PARSER_ERROR = "parser_error"
|
|
28
|
+
PARSER_LOG = "parser_log"
|
|
29
|
+
|
|
30
|
+
# Session events
|
|
31
|
+
SESSION_STARTED = "session_started"
|
|
32
|
+
SESSION_COMPLETED = "session_completed"
|
|
33
|
+
SESSION_FAILED = "session_failed"
|
|
34
|
+
|
|
35
|
+
# Command events
|
|
36
|
+
COMMAND_ISSUED = "command_issued"
|
|
37
|
+
COMMAND_COMPLETED = "command_completed"
|
|
38
|
+
COMMAND_FAILED = "command_failed"
|
|
39
|
+
|
|
40
|
+
# System events
|
|
41
|
+
SYSTEM_STARTUP = "system_startup"
|
|
42
|
+
SYSTEM_SHUTDOWN = "system_shutdown"
|
|
43
|
+
SYSTEM_ERROR = "system_error"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class SystemEventType(str, Enum):
|
|
47
|
+
"""
|
|
48
|
+
System event types for Django database storage.
|
|
49
|
+
|
|
50
|
+
These match the choices in Django's SystemEvent model.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Parser events
|
|
54
|
+
PARSER_REGISTERED = "parser_registered"
|
|
55
|
+
PARSER_HEARTBEAT = "parser_heartbeat"
|
|
56
|
+
PARSER_DISCONNECTED = "parser_disconnected"
|
|
57
|
+
PARSER_ERROR = "parser_error"
|
|
58
|
+
|
|
59
|
+
# Session events
|
|
60
|
+
SESSION_STARTED = "session_started"
|
|
61
|
+
SESSION_COMPLETED = "session_completed"
|
|
62
|
+
SESSION_FAILED = "session_failed"
|
|
63
|
+
|
|
64
|
+
# Command events
|
|
65
|
+
COMMAND_ISSUED = "command_issued"
|
|
66
|
+
COMMAND_COMPLETED = "command_completed"
|
|
67
|
+
COMMAND_FAILED = "command_failed"
|
|
68
|
+
|
|
69
|
+
# System events
|
|
70
|
+
SYSTEM_STARTUP = "system_startup"
|
|
71
|
+
SYSTEM_SHUTDOWN = "system_shutdown"
|
|
72
|
+
SYSTEM_ERROR = "system_error"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class RedisEventType(str, Enum):
|
|
76
|
+
"""
|
|
77
|
+
Redis PubSub event types.
|
|
78
|
+
|
|
79
|
+
These are the event types published to Redis channels
|
|
80
|
+
for inter-service communication.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
# Driver lifecycle (from RPC to Django)
|
|
84
|
+
DRIVER_REGISTER = "driver_register"
|
|
85
|
+
DRIVER_DISCONNECT = "driver_disconnect"
|
|
86
|
+
|
|
87
|
+
# Parser events (internal Django events)
|
|
88
|
+
PARSER_HEARTBEAT = "parser_heartbeat"
|
|
89
|
+
PARSER_LOG = "parser_log"
|
|
90
|
+
|
|
91
|
+
# Session events
|
|
92
|
+
SESSION_STARTED = "session_started"
|
|
93
|
+
SESSION_COMPLETED = "session_completed"
|
|
94
|
+
SESSION_FAILED = "session_failed"
|
|
95
|
+
|
|
96
|
+
# Command events
|
|
97
|
+
COMMAND_COMPLETED = "command_completed"
|
|
98
|
+
COMMAND_FAILED = "command_failed"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ARQ job name enums for UnrealOn system.
|
|
3
|
+
|
|
4
|
+
Centralized job name definitions used across all services.
|
|
5
|
+
"""
|
|
6
|
+
from enum import Enum
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ARQJobName(str, Enum):
|
|
10
|
+
"""
|
|
11
|
+
ARQ job names used in the system.
|
|
12
|
+
|
|
13
|
+
These are the job function names that can be enqueued
|
|
14
|
+
and processed by ARQ workers.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# Driver management jobs
|
|
18
|
+
REGISTER_DRIVER = "register_driver"
|
|
19
|
+
DRIVER_DISCONNECT = "driver_disconnect"
|
|
20
|
+
GET_DRIVER_STATUS = "get_driver_status"
|
|
21
|
+
LIST_AVAILABLE_DRIVERS = "list_available_drivers"
|
|
22
|
+
|
|
23
|
+
# Task management jobs
|
|
24
|
+
ASSIGN_TASK_TO_DRIVER = "assign_task_to_driver"
|
|
25
|
+
|
|
26
|
+
# System jobs
|
|
27
|
+
PING = "ping"
|
|
28
|
+
PROCESS_DRIVER_HEARTBEAT = "process_driver_heartbeat"
|
|
29
|
+
|
|
30
|
+
# Lifecycle jobs
|
|
31
|
+
STARTUP = "startup"
|
|
32
|
+
SHUTDOWN = "shutdown"
|
|
@@ -58,6 +58,7 @@ class MessageType(str, Enum):
|
|
|
58
58
|
PONG = "pong" # Pong response
|
|
59
59
|
ERROR = "error" # Error message
|
|
60
60
|
ACK = "ack" # Acknowledgment
|
|
61
|
+
MONITOR_REGISTER = "monitor_register" # Monitor client registration
|
|
61
62
|
|
|
62
63
|
def is_driver_lifecycle(self) -> bool:
|
|
63
64
|
"""Check if message is related to driver lifecycle."""
|
|
@@ -46,6 +46,11 @@ from .logging import (
|
|
|
46
46
|
LogMetrics
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
+
from .authentication import (
|
|
50
|
+
APIKeyAuthRequest,
|
|
51
|
+
APIKeyAuthResponse
|
|
52
|
+
)
|
|
53
|
+
|
|
49
54
|
__all__ = [
|
|
50
55
|
# Base models
|
|
51
56
|
"UnrealOnBaseModel",
|
|
@@ -76,4 +81,8 @@ __all__ = [
|
|
|
76
81
|
"LogEntry",
|
|
77
82
|
"LogQuery",
|
|
78
83
|
"LogMetrics",
|
|
84
|
+
|
|
85
|
+
# Authentication models
|
|
86
|
+
"APIKeyAuthRequest",
|
|
87
|
+
"APIKeyAuthResponse",
|
|
79
88
|
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Authentication models for UnrealOn system.
|
|
3
|
+
|
|
4
|
+
Provides Pydantic models for API key authentication between services.
|
|
5
|
+
"""
|
|
6
|
+
from typing import Optional, List
|
|
7
|
+
from pydantic import Field
|
|
8
|
+
|
|
9
|
+
from .base import UnrealOnBaseModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class APIKeyAuthRequest(UnrealOnBaseModel):
|
|
13
|
+
"""API key authentication request."""
|
|
14
|
+
api_key: str = Field(min_length=1, description="API key for authentication")
|
|
15
|
+
parser_id: str = Field(min_length=1, description="Parser requesting authentication")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class APIKeyAuthResponse(UnrealOnBaseModel):
|
|
19
|
+
"""API key authentication response."""
|
|
20
|
+
success: bool = Field(description="Whether authentication was successful")
|
|
21
|
+
user_id: Optional[int] = Field(default=None, description="Authenticated user ID")
|
|
22
|
+
username: Optional[str] = Field(default=None, description="Authenticated username")
|
|
23
|
+
permissions: List[str] = Field(default_factory=list, description="User permissions")
|
|
24
|
+
error: Optional[str] = Field(default=None, description="Error message if failed")
|
|
@@ -14,6 +14,7 @@ class BrowserManagerConfig(ManagerConfig):
|
|
|
14
14
|
|
|
15
15
|
headless: bool = Field(default=True, description="Run headless")
|
|
16
16
|
parser_name: str = Field(..., description="Parser name for browser")
|
|
17
|
+
stealth_warmup_enabled: bool = Field(default=False, description="Enable stealth warmup")
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class BrowserManager(BaseManager):
|
|
@@ -51,7 +52,10 @@ class BrowserManager(BaseManager):
|
|
|
51
52
|
self.logger.info("🚀 Starting browser (lazy initialization)...")
|
|
52
53
|
|
|
53
54
|
# Create browser config
|
|
54
|
-
browser_config = BrowserConfig(
|
|
55
|
+
browser_config = BrowserConfig(
|
|
56
|
+
parser_name=self.config.parser_name,
|
|
57
|
+
stealth_warmup_enabled=self.config.stealth_warmup_enabled # Disable stealth warmup to avoid scanner navigation
|
|
58
|
+
)
|
|
55
59
|
|
|
56
60
|
# Create browser manager
|
|
57
61
|
self.browser = CoreBrowserManager(browser_config)
|
|
@@ -96,3 +100,19 @@ class BrowserManager(BaseManager):
|
|
|
96
100
|
self.logger.error(f"Get HTML failed: {e}")
|
|
97
101
|
self.stats.record_operation(False, 0.0)
|
|
98
102
|
return None
|
|
103
|
+
|
|
104
|
+
async def execute_script_async(self, script: str) -> any:
|
|
105
|
+
"""Execute JavaScript on current page via ScriptManager."""
|
|
106
|
+
# Ensure browser is initialized
|
|
107
|
+
if not await self._ensure_browser_initialized():
|
|
108
|
+
raise RuntimeError("Failed to initialize browser")
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
# Use ScriptManager from CoreBrowserManager
|
|
112
|
+
result = await self.browser.script_manager.execute_script(script)
|
|
113
|
+
self.stats.record_operation(True, 0.0)
|
|
114
|
+
return result
|
|
115
|
+
except Exception as e:
|
|
116
|
+
self.logger.error(f"Script execution failed: {e}")
|
|
117
|
+
self.stats.record_operation(False, 0.0)
|
|
118
|
+
raise
|
|
@@ -25,6 +25,7 @@ unrealon-browser/src/unrealon_browser/managers/cookies.py
|
|
|
25
25
|
unrealon-browser/src/unrealon_browser/managers/logger_bridge.py
|
|
26
26
|
unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py
|
|
27
27
|
unrealon-browser/src/unrealon_browser/managers/profile.py
|
|
28
|
+
unrealon-browser/src/unrealon_browser/managers/script_manager.py
|
|
28
29
|
unrealon-browser/src/unrealon_browser/stealth/__init__.py
|
|
29
30
|
unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.pyc
|
|
30
31
|
unrealon-browser/src/unrealon_browser/stealth/manager.pyc
|
|
@@ -38,6 +39,8 @@ unrealon-core/src/unrealon_core/config/__init__.py
|
|
|
38
39
|
unrealon-core/src/unrealon_core/config/environment.py
|
|
39
40
|
unrealon-core/src/unrealon_core/config/urls.py
|
|
40
41
|
unrealon-core/src/unrealon_core/enums/__init__.py
|
|
42
|
+
unrealon-core/src/unrealon_core/enums/events.py
|
|
43
|
+
unrealon-core/src/unrealon_core/enums/jobs.py
|
|
41
44
|
unrealon-core/src/unrealon_core/enums/status.py
|
|
42
45
|
unrealon-core/src/unrealon_core/enums/types.py
|
|
43
46
|
unrealon-core/src/unrealon_core/error_handling/__init__.py
|
|
@@ -55,6 +58,7 @@ unrealon-core/src/unrealon_core/exceptions/validation.py
|
|
|
55
58
|
unrealon-core/src/unrealon_core/models/__init__.py
|
|
56
59
|
unrealon-core/src/unrealon_core/models/arq_context.py
|
|
57
60
|
unrealon-core/src/unrealon_core/models/arq_responses.py
|
|
61
|
+
unrealon-core/src/unrealon_core/models/authentication.py
|
|
58
62
|
unrealon-core/src/unrealon_core/models/base.py
|
|
59
63
|
unrealon-core/src/unrealon_core/models/bridge_stats.py
|
|
60
64
|
unrealon-core/src/unrealon_core/models/communication.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/cli/interactive_mode.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/bot_detection.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/dataclasses.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/detection.py
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/dto/models/statistics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/managers/logger_bridge.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.pyc
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.pyc
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/__init__.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/error_context.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/error_handling/recovery.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/exceptions/communication.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/connection_stats.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/broadcast.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/config.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/driver.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/errors.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket/logging.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/models/websocket_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-core/src/unrealon_core/monitoring/health_check.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/event_manager.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/protocols.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/core_module/registry.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/decorators/schedule.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py
RENAMED
|
File without changes
|
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py
RENAMED
|
File without changes
|
{unrealon-2.0.7 → unrealon-2.0.9}/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|