"""server.py — tradein-browser service main process. Этот модуль запускается как точка входа контейнера ``tradein-browser``. Он читает конфигурацию из переменных окружения и вызывает ``camoufox.server.launch_server`` для экспозиции Playwright WS-эндпоинта, к которому подключается ``tradein-backend`` через ``playwright.firefox.connect``. Переменные окружения: BROWSER_PORT — TCP-порт WS-сервера (default: 3000) SCRAPER_PROXY_URL — прокси URL формата ``http://user:pass@host:port`` (опционально) WS-эндпоинт доступен внутри Docker-сети как ``ws://tradein-browser:/playwright``. """ import logging import os from urllib.parse import urlparse logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") logger = logging.getLogger(__name__) def _parse_proxy(proxy_url: str | None) -> dict[str, str] | None: """Парсит proxy URL → playwright proxy dict. Формат входного URL: ``http://user:pass@host:port`` или ``http://host:port``. Возвращает None если proxy_url пуст. Returns: ``{"server": "http://host:port", "username": "...", "password": "..."}`` или None. """ if not proxy_url: return None parsed = urlparse(proxy_url) port_part = f":{parsed.port}" if parsed.port else "" server = f"{parsed.scheme}://{parsed.hostname}{port_part}" result: dict[str, str] = {"server": server} if parsed.username: result["username"] = parsed.username if parsed.password: result["password"] = parsed.password return result def main() -> None: port = int(os.environ.get("BROWSER_PORT", "3000")) proxy_url = os.environ.get("SCRAPER_PROXY_URL") proxy = _parse_proxy(proxy_url) logger.info( "tradein-browser: запуск camoufox WS-сервера на порту %d (proxy=%s)", port, proxy is not None, ) # Импортируем camoufox.server здесь — в контейнере Firefox уже установлен. from camoufox.server import launch_server # noqa: PLC0415 kwargs: dict[str, object] = { "headless": True, "os": "windows", "locale": "ru-RU", "geoip": True, "humanize": True, "port": port, # port передаётся через **launch_options в launch_options() → прокидывается # в Playwright launchServer({ port: N }) — сервер слушает на заданном порту. } if proxy is not None: kwargs["proxy"] = proxy # launch_server блокируется — это основной процесс контейнера. launch_server(**kwargs) # type: ignore[arg-type] if __name__ == "__main__": main()