# tradein-browser — camoufox Playwright WS server (изолированный контейнер Firefox).
# Backend подключается к этому контейнеру через playwright.firefox.connect.

FROM python:3.12-slim

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1

# Firefox runtime libs + ca-certificates для TLS
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get install -y --no-install-recommends \
    libgtk-3-0 \
    libasound2 \
    libdbus-glib-1-2 \
    libx11-xcb1 \
    libxtst6 \
    ca-certificates \
    && useradd --create-home --uid 1000 app

WORKDIR /app

# camoufox[geoip] тянет playwright как зависимость
RUN pip install --no-cache-dir "camoufox[geoip]" aiohttp

# ── #915/#918: null-guard + ВАЛИДНЫЕ дефолты для pageError.location (playwright 1.60.0) ─
# Firefox/juggler-бэкенд иногда отдаёт uncaught JS-ошибку страницы (реклама /
# cross-origin скрипты / anti-bot challenge на avito) БЕЗ поля location.
# playwright при доставке pageError-события собирает
#   { url: pageError.location.url, line: ...lineNumber, column: ...columnNumber }
# (coreBundle.js, 2 места: BrowserContextDispatcher + trace event).
#
# Двухслойный баг (оба рвут protocol-соединение → "Connection closed while reading
# from the driver" / TargetClosedError → server.py 500 + relaunch браузера):
#   1. без guard → `pageError.location.url` бросает
#      `TypeError: Cannot read properties of undefined (reading 'url')`;
#   2. ОДНОГО optional-chaining (`?.url`) НЕДОСТАТОЧНО (это была дыра #918):
#      url станет undefined, а protocol-валидатор `tString` требует string →
#      `ValidationError: location.url: expected string, got undefined`.
# Поэтому даём валидные дефолты: url → '', line/column → 0 — проходят валидатор,
# событие доставляется без краша. Профит: browser возвращает HTML challenge-
# страницы вместо краша → pipeline видит firewall и штатно ротирует IP, а не
# уходит в crash-storm (подтверждено прод-дебагом локального стека 2026-05-31).
#
# Апгрейд playwright невозможен — camoufox 0.4.11 pinned под Firefox+juggler.
# Сборка падает (exit 1), если паттерн не найден — сигнал что bump playwright сломал патч.
RUN PW_BUNDLE="$(python -c 'import os,playwright;print(os.path.join(os.path.dirname(playwright.__file__),"driver","package","lib","coreBundle.js"))')" \
    && sed -i -E "s/pageError\.location\.url,/pageError.location?.url ?? '',/g" "$PW_BUNDLE" \
    && sed -i -E 's/pageError\.location\.lineNumber,/pageError.location?.lineNumber ?? 0,/g' "$PW_BUNDLE" \
    && sed -i -E 's/pageError\.location\.columnNumber/pageError.location?.columnNumber ?? 0/g' "$PW_BUNDLE" \
    && N="$(grep -cF "pageError.location?.url ?? ''" "$PW_BUNDLE")" \
    && echo "tradein-browser: patched pageError.location?.url ?? '' sites: $N" \
    && [ "$N" -ge 2 ]

COPY server.py ./server.py

# camoufox fetch качает (а) Firefox-сборку и (б) GeoLite2 mmdb (geoip=True).
# Firefox идёт в $HOME/.cache → ENV HOME=/home/app кладёт его в кэш app-юзера,
# куда рантайм его ищет (фикс #899). НО mmdb пишется в site-packages пакета
# camoufox (root-owned после pip install) — под app это PermissionError на
# GeoLite2-City.mmdb. Поэтому fetch выполняем под ROOT (пишет и mmdb, и —
# благодаря ENV HOME — Firefox в /home/app/.cache), затем chown'им Firefox-кэш
# на app. mmdb остаётся root-owned в site-packages (world-readable → app читает
# на рантайме). Verified реальной сборкой образа 2026-05-31.
ENV HOME=/home/app

RUN python -m camoufox fetch && chown -R app:app /home/app/.cache

USER app

EXPOSE 3000

CMD ["python", "server.py"]
