Proxy auth UI, verbose Live logs, build script, docs
- Fixed exit and manual chain: optional user/pass fields with URL merge and redaction in UI/logs - config: split_proxy_for_edit, merge_proxy_credentials, redact_proxy_url, IPv6-style host bracketing - Live tab: UILogHandler to stream proxy_chain_manager logs; Verbose toggle; Clear log; httpx quiet - service/validator/fetcher: structured INFO/DEBUG for pool, GOST, validation, fetches - setup_and_build.ps1: pip upgrade, deps, PyInstaller, desktop copy + shortcut; build_exe.bat delegates - README: clone/pull to one-script desktop build flow Made-with: Cursor
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
from typing import Callable
|
||||
|
||||
import httpx
|
||||
@@ -51,35 +52,70 @@ async def validate_proxies(
|
||||
lock = asyncio.Lock()
|
||||
total = len(proxy_urls)
|
||||
done = 0
|
||||
c = max(1, concurrency)
|
||||
waves = (total + c - 1) // c
|
||||
cap = min(600.0, float(waves) * float(timeout_seconds) + 45.0)
|
||||
cap = max(90.0, cap)
|
||||
log.info(
|
||||
"validate_proxies: n=%d concurrency=%d per_timeout=%.1fs wall_cap~=%.0fs check=%s",
|
||||
total,
|
||||
c,
|
||||
timeout_seconds,
|
||||
cap,
|
||||
(check_url[:70] + "…") if len(check_url) > 70 else check_url,
|
||||
)
|
||||
|
||||
async def one(u: str) -> None:
|
||||
nonlocal done
|
||||
async with sem:
|
||||
good = await _check_one(u, check_url, timeout_seconds)
|
||||
async with lock:
|
||||
done += 1
|
||||
if good:
|
||||
ok.append(u)
|
||||
if on_progress:
|
||||
on_progress(done, total)
|
||||
|
||||
await asyncio.gather(*(one(u) for u in proxy_urls))
|
||||
return ok
|
||||
|
||||
|
||||
async def _check_one(proxy_url: str, check_url: str, timeout_seconds: float) -> bool:
|
||||
t = httpx.Timeout(timeout_seconds, connect=min(8.0, timeout_seconds))
|
||||
lim = max(32, min(256, c * 8))
|
||||
limits = httpx.Limits(max_connections=lim, max_keepalive_connections=max(16, c * 4))
|
||||
|
||||
last_prog_t = 0.0
|
||||
prog_step = max(1, total // 120)
|
||||
|
||||
async def _run_all(client: httpx.AsyncClient) -> None:
|
||||
nonlocal done, last_prog_t
|
||||
|
||||
async def one(u: str) -> None:
|
||||
nonlocal done, last_prog_t
|
||||
async with sem:
|
||||
try:
|
||||
r = await client.get(check_url, proxy=u)
|
||||
good = r.status_code == 200 and len(r.content) > 0
|
||||
except Exception:
|
||||
good = False
|
||||
async with lock:
|
||||
done += 1
|
||||
if good:
|
||||
ok.append(u)
|
||||
if on_progress:
|
||||
now = time.monotonic()
|
||||
if (
|
||||
done == total
|
||||
or done == 1
|
||||
or done % prog_step == 0
|
||||
or (now - last_prog_t) >= 0.1
|
||||
):
|
||||
last_prog_t = now
|
||||
on_progress(done, total)
|
||||
|
||||
await asyncio.gather(*(one(u) for u in proxy_urls))
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(
|
||||
proxy=proxy_url,
|
||||
timeout=t,
|
||||
verify=False, # many proxies have self-signed or no TLS
|
||||
verify=False,
|
||||
follow_redirects=True,
|
||||
) as c:
|
||||
r = await c.get(check_url)
|
||||
return r.status_code == 200 and len(r.content) > 0
|
||||
except Exception:
|
||||
return False
|
||||
limits=limits,
|
||||
) as client:
|
||||
await asyncio.wait_for(_run_all(client), timeout=cap)
|
||||
except asyncio.TimeoutError:
|
||||
log.warning(
|
||||
"validate_proxies wall-clock cap %.0fs exceeded (%d URLs) — returning partial results",
|
||||
cap,
|
||||
total,
|
||||
)
|
||||
log.info("validate_proxies: finished ok=%d / %d", len(ok), total)
|
||||
return ok
|
||||
|
||||
|
||||
async def check_chain_exit_ip(
|
||||
@@ -92,6 +128,12 @@ async def check_chain_exit_ip(
|
||||
per = max(5.0, min(20.0, float(timeout_seconds)))
|
||||
budget = max(15.0, min(60.0, float(timeout_seconds) * 2 + 5.0))
|
||||
urls = [check_url] + [u for u in _IP_FALLBACKS if u != check_url][:2]
|
||||
log.debug(
|
||||
"check_chain_exit_ip: budget=%.1fs per_req=%.1fs fallback_count=%d",
|
||||
budget,
|
||||
per,
|
||||
len(urls),
|
||||
)
|
||||
|
||||
async def _run() -> str | None:
|
||||
t = httpx.Timeout(per, connect=min(8.0, per))
|
||||
|
||||
Reference in New Issue
Block a user