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:
Dr Jones
2026-04-16 00:27:39 -07:00
parent 0316b1befc
commit 214d2d2ff7
9 changed files with 495 additions and 89 deletions

View File

@@ -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))