Spaces:
Paused
Paused
| import argparse | |
| import os | |
| import re | |
| import sys | |
| from typing import Dict, Optional | |
| from launcher.utils import get_proxy_from_gsettings | |
| # --- Configuration Constants --- | |
| PYTHON_EXECUTABLE = sys.executable | |
| ENDPOINT_CAPTURE_TIMEOUT = int(os.environ.get("ENDPOINT_CAPTURE_TIMEOUT", "45")) | |
| DEFAULT_SERVER_PORT = int(os.environ.get("DEFAULT_FASTAPI_PORT", "2048")) | |
| DEFAULT_CAMOUFOX_PORT = int(os.environ.get("DEFAULT_CAMOUFOX_PORT", "9222")) | |
| DEFAULT_STREAM_PORT = int(os.environ.get("STREAM_PORT", "3120")) | |
| DEFAULT_HELPER_ENDPOINT = os.environ.get("GUI_DEFAULT_HELPER_ENDPOINT", "") | |
| DEFAULT_AUTH_SAVE_TIMEOUT = int(os.environ.get("AUTH_SAVE_TIMEOUT", "30")) | |
| DEFAULT_SERVER_LOG_LEVEL = os.environ.get("SERVER_LOG_LEVEL", "INFO") | |
| AUTH_PROFILES_DIR = os.path.join( | |
| os.path.dirname(os.path.dirname(__file__)), "auth_profiles" | |
| ) | |
| ACTIVE_AUTH_DIR = os.path.join(AUTH_PROFILES_DIR, "active") | |
| SAVED_AUTH_DIR = os.path.join(AUTH_PROFILES_DIR, "saved") | |
| LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "logs") | |
| LAUNCHER_LOG_FILE_PATH = os.path.join(LOG_DIR, "launch_app.log") | |
| DIRECT_LAUNCH = os.environ.get("DIRECT_LAUNCH", "").lower() in ("true", "1", "yes") | |
| ws_regex = re.compile(r"(ws://\S+)") | |
| def determine_proxy_configuration( | |
| internal_camoufox_proxy_arg: Optional[str] = None, | |
| ) -> Dict[str, Optional[str]]: | |
| """ | |
| Unified proxy configuration determination function. | |
| Priority: Command-line arguments > Environment variables > System settings. | |
| """ | |
| result = {"camoufox_proxy": None, "stream_proxy": None, "source": "No Proxy"} | |
| if internal_camoufox_proxy_arg is not None: | |
| if internal_camoufox_proxy_arg.strip(): | |
| result["camoufox_proxy"] = internal_camoufox_proxy_arg.strip() | |
| result["stream_proxy"] = internal_camoufox_proxy_arg.strip() | |
| result["source"] = ( | |
| f"CLI argument --internal-camoufox-proxy: {internal_camoufox_proxy_arg.strip()}" | |
| ) | |
| else: | |
| result["source"] = ( | |
| "CLI argument --internal-camoufox-proxy='' (Explicitly disabled)" | |
| ) | |
| return result | |
| unified_proxy = os.environ.get("UNIFIED_PROXY_CONFIG") | |
| if unified_proxy: | |
| result["camoufox_proxy"] = unified_proxy | |
| result["stream_proxy"] = unified_proxy | |
| result["source"] = f"Environment variable UNIFIED_PROXY_CONFIG: {unified_proxy}" | |
| return result | |
| http_proxy = os.environ.get("HTTP_PROXY") | |
| if http_proxy: | |
| result["camoufox_proxy"] = http_proxy | |
| result["stream_proxy"] = http_proxy | |
| result["source"] = f"Environment variable HTTP_PROXY: {http_proxy}" | |
| return result | |
| https_proxy = os.environ.get("HTTPS_PROXY") | |
| if https_proxy: | |
| result["camoufox_proxy"] = https_proxy | |
| result["stream_proxy"] = https_proxy | |
| result["source"] = f"Environment variable HTTPS_PROXY: {https_proxy}" | |
| return result | |
| if sys.platform.startswith("linux"): | |
| gsettings_proxy = get_proxy_from_gsettings() | |
| if gsettings_proxy: | |
| result["camoufox_proxy"] = gsettings_proxy | |
| result["stream_proxy"] = gsettings_proxy | |
| result["source"] = f"gsettings System Proxy: {gsettings_proxy}" | |
| return result | |
| return result | |
| def parse_args() -> argparse.Namespace: | |
| # Resolve defaults at call time to avoid module-import-time env pinning | |
| # (e.g., test sessions that override STREAM_PORT globally). | |
| runtime_default_server_port = int( | |
| os.environ.get("DEFAULT_FASTAPI_PORT", str(DEFAULT_SERVER_PORT)) | |
| ) | |
| runtime_default_stream_port = int( | |
| os.environ.get("STREAM_PORT", str(DEFAULT_STREAM_PORT)) | |
| ) | |
| runtime_default_camoufox_port = int( | |
| os.environ.get("DEFAULT_CAMOUFOX_PORT", str(DEFAULT_CAMOUFOX_PORT)) | |
| ) | |
| runtime_default_helper_endpoint = os.environ.get( | |
| "GUI_DEFAULT_HELPER_ENDPOINT", DEFAULT_HELPER_ENDPOINT | |
| ) | |
| runtime_default_auth_save_timeout = int( | |
| os.environ.get("AUTH_SAVE_TIMEOUT", str(DEFAULT_AUTH_SAVE_TIMEOUT)) | |
| ) | |
| runtime_default_server_log_level = os.environ.get( | |
| "SERVER_LOG_LEVEL", DEFAULT_SERVER_LOG_LEVEL | |
| ) | |
| parser = argparse.ArgumentParser( | |
| description="Launcher for Camoufox browser simulation and FastAPI proxy server.", | |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter, | |
| ) | |
| # Internal parameters | |
| parser.add_argument( | |
| "--internal-launch-mode", | |
| type=str, | |
| choices=["debug", "headless", "virtual_headless"], | |
| help=argparse.SUPPRESS, | |
| ) | |
| parser.add_argument( | |
| "--internal-auth-file", type=str, default=None, help=argparse.SUPPRESS | |
| ) | |
| parser.add_argument( | |
| "--internal-camoufox-port", | |
| type=int, | |
| default=runtime_default_camoufox_port, | |
| help=argparse.SUPPRESS, | |
| ) | |
| parser.add_argument( | |
| "--internal-camoufox-proxy", type=str, default=None, help=argparse.SUPPRESS | |
| ) | |
| parser.add_argument( | |
| "--internal-camoufox-os", type=str, default="random", help=argparse.SUPPRESS | |
| ) | |
| # User-visible parameters | |
| parser.add_argument( | |
| "--server-port", | |
| type=int, | |
| default=runtime_default_server_port, | |
| help=f"FastAPI server listening port (Default: {runtime_default_server_port})", | |
| ) | |
| parser.add_argument( | |
| "--stream-port", | |
| type=int, | |
| default=runtime_default_stream_port, | |
| help=f"Streaming proxy server port. Provide 0 to disable. Default: {runtime_default_stream_port}", | |
| ) | |
| parser.add_argument( | |
| "--helper", | |
| type=str, | |
| default=runtime_default_helper_endpoint, | |
| help=f"Helper server getStreamResponse endpoint. Provide empty string to disable. Default: {runtime_default_helper_endpoint}", | |
| ) | |
| parser.add_argument( | |
| "--camoufox-debug-port", | |
| type=int, | |
| default=runtime_default_camoufox_port, | |
| help=f"Internal Camoufox instance debugging port (Default: {runtime_default_camoufox_port})", | |
| ) | |
| mode_selection_group = parser.add_mutually_exclusive_group() | |
| mode_selection_group.add_argument( | |
| "--debug", | |
| action="store_true", | |
| help="Start in debug mode (browser visible, interactive auth allowed)", | |
| ) | |
| mode_selection_group.add_argument( | |
| "--headless", | |
| action="store_true", | |
| help="Start in headless mode (no browser UI, requires pre-saved auth)", | |
| ) | |
| mode_selection_group.add_argument( | |
| "--virtual-display", | |
| action="store_true", | |
| help="Start in headless mode with virtual display (Xvfb, Linux only)", | |
| ) | |
| parser.add_argument( | |
| "--active-auth-json", | |
| type=str, | |
| default=None, | |
| help="[Optional] Path to active authentication JSON file.", | |
| ) | |
| debug_logs_default = os.environ.get("DEBUG_LOGS_ENABLED", "false").lower() == "true" | |
| trace_logs_default = os.environ.get("TRACE_LOGS_ENABLED", "false").lower() == "true" | |
| auto_save_auth_default = os.environ.get("AUTO_SAVE_AUTH", "false").lower() == "true" | |
| parser.add_argument( | |
| "--auto-save-auth", | |
| action="store_true", | |
| help="[Debug Mode] Automatically prompt and save new auth state after successful login.", | |
| ) | |
| parser.add_argument( | |
| "--save-auth-as", | |
| type=str, | |
| default=None, | |
| help="[Debug Mode] Filename for the new auth file (without .json extension).", | |
| ) | |
| parser.add_argument( | |
| "--auth-save-timeout", | |
| type=int, | |
| default=runtime_default_auth_save_timeout, | |
| help=f"[Debug Mode] Timeout in seconds to wait for auth save. Default: {runtime_default_auth_save_timeout}", | |
| ) | |
| parser.add_argument( | |
| "--exit-on-auth-save", | |
| action="store_true", | |
| help="[Debug Mode] Automatically close the launcher and processes after saving new auth file.", | |
| ) | |
| parser.add_argument( | |
| "--server-log-level", | |
| type=str, | |
| default=runtime_default_server_log_level, | |
| choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], | |
| help=f"Log level for server.py. Default: {runtime_default_server_log_level}", | |
| ) | |
| parser.add_argument( | |
| "--server-redirect-print", | |
| action="store_true", | |
| help="Redirect server.py print output to its logging system.", | |
| ) | |
| parser.add_argument( | |
| "--debug-logs", | |
| action="store_true", | |
| default=debug_logs_default, | |
| help="Enable internal DEBUG logs for server.py (DEBUG_LOGS_ENABLED env).", | |
| ) | |
| parser.add_argument( | |
| "--trace-logs", | |
| action="store_true", | |
| default=trace_logs_default, | |
| help="Enable internal TRACE logs for server.py (TRACE_LOGS_ENABLED env).", | |
| ) | |
| parser.add_argument( | |
| "--skip-frontend-build", | |
| action="store_true", | |
| help="Skip frontend build check (for environments without Node.js/npm).", | |
| ) | |
| args = parser.parse_args() | |
| # Mark which arguments were explicitly set via CLI | |
| args.debug_logs_from_cli = "--debug-logs" in sys.argv | |
| args.trace_logs_from_cli = "--trace-logs" in sys.argv | |
| args.auto_save_auth_from_cli = "--auto-save-auth" in sys.argv | |
| args.server_redirect_print_from_cli = "--server-redirect-print" in sys.argv | |
| # Use environment variables if not set via CLI | |
| if not args.debug_logs_from_cli: | |
| args.debug_logs = debug_logs_default | |
| if not args.trace_logs_from_cli: | |
| args.trace_logs = trace_logs_default | |
| if not args.auto_save_auth_from_cli: | |
| args.auto_save_auth = auto_save_auth_default | |
| return args | |