#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import annotations import threading import time from typing import Optional from app_logger import get_logger from browser_installer import check_and_install_browser from playwright_automation import PlaywrightBrowserManager logger = get_logger("browser_manager") _browser_manager: Optional[PlaywrightBrowserManager] = None _lock = threading.Lock() _cond = threading.Condition(_lock) _init_in_progress = False _init_error: Optional[str] = None _init_thread: Optional[threading.Thread] = None def get_browser_manager() -> Optional[PlaywrightBrowserManager]: return _browser_manager def is_browser_manager_ready() -> bool: return _browser_manager is not None def get_browser_manager_init_error() -> Optional[str]: return _init_error def init_browser_manager(*, block: bool = True, timeout: Optional[float] = None) -> bool: global _browser_manager global _init_in_progress, _init_error deadline = time.monotonic() + float(timeout) if timeout is not None else None with _cond: if _browser_manager is not None: return True if _init_in_progress: if not block: return False while _init_in_progress: if deadline is None: _cond.wait(timeout=0.5) continue remaining = deadline - time.monotonic() if remaining <= 0: break _cond.wait(timeout=min(0.5, remaining)) return _browser_manager is not None _init_in_progress = True _init_error = None ok = False error: Optional[str] = None manager: Optional[PlaywrightBrowserManager] = None try: logger.info("正在初始化Playwright浏览器管理器...") if not check_and_install_browser(log_callback=lambda msg, account_id=None: logger.info(str(msg))): error = "浏览器环境检查失败" logger.error("浏览器环境检查失败!") ok = False else: manager = PlaywrightBrowserManager( headless=True, log_callback=lambda msg, account_id=None: logger.info(str(msg)), ) ok = True logger.info("Playwright浏览器管理器创建成功!") except Exception as exc: error = f"{type(exc).__name__}: {exc}" logger.exception("初始化Playwright浏览器管理器时发生异常") ok = False with _cond: if ok and manager is not None: _browser_manager = manager else: _init_error = error or "初始化失败" _init_in_progress = False _cond.notify_all() return ok def init_browser_manager_async() -> None: """异步初始化浏览器环境,避免阻塞 Web 请求/服务启动。""" global _init_thread def _worker(): try: init_browser_manager(block=True) except Exception: logger.exception("异步初始化浏览器管理器失败") with _cond: if _browser_manager is not None: return if _init_thread and _init_thread.is_alive(): return if _init_in_progress: return _init_thread = threading.Thread(target=_worker, daemon=True, name="browser-manager-init") _init_thread.start()