fix: слоты, безопасность, единый формат ответа и валидация
- слоты браузеров: asyncio.Semaphore, размер из BROWSER_SLOTS, при нехватке — 503 + Retry-After; устранена утечка счётчика при отказе (#12, #49) - session_id принимается только как UUID, путь профиля проверяется (#5) - секреты клиента в логах маскируются, полный дамп — только на DEBUG (#6) - ответ: status всегда "ok"/"err", поле code (no_slots / request_failed / challenge_failed / action_failed), response_model (#7) - непройденный антибот → challenge_failed, действия не выполняются (#8) - таймауты провайдеров в мс вынесены в константы; detect переживает навигацию посреди проверки; пауза между неудачными solve вместо холостого цикла (#9) - обязательные поля действий и формат прокси проверяются схемой → 422 до запуска браузера (#13) - прокси необязателен (#15) - user_agent сохраняется в профиле сессии и реально передаётся в браузер (#16) - duration_ms у действий и у запроса (#18), опция screenshot (#19) - общий конфиг логирования (LOG_LEVEL), print → логгер, CloudflareProvider, удалён cached_persistent, GET /health (#22) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f58306cbb4
commit
437ea27be7
14 files changed
+360
-201
No files matched your search
+7
-6
@@ -35,15 +35,16 @@ def classify(resp: httpx.Response | Exception) -> str:
|
||||
if isinstance(resp, Exception):
|
||||
return f"exc:{type(resp).__name__}"
|
||||
data = resp.json()
|
||||
if "No slots" in str(data.get("error", "")):
|
||||
code = data.get("code")
|
||||
if code == "no_slots":
|
||||
return "no_slots"
|
||||
actions = data.get("actions") or []
|
||||
if not actions:
|
||||
return f"error:{str(data.get('error'))[:60]}"
|
||||
last = actions[-1]
|
||||
if not last.get("ok") or last.get("result"):
|
||||
if code == "challenge_failed":
|
||||
return "cf_blocked"
|
||||
if code == "action_failed":
|
||||
html = data.get("html") or ""
|
||||
return "cf_blocked" if any(m in html for m in CF_MARKERS) else "action_failed"
|
||||
if data.get("status") != "ok":
|
||||
return f"error:{str(data.get('error'))[:60]}"
|
||||
return "ok"
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user