Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

proxy-selector

Minimal multi-device proxy selector that benchmarks V2Ray/Xray configs from the user's real network, ranks them per traffic type, and emits a v2rayNG subscription of the winners. See docs/DESIGN.md and docs/adr/.

Status

Phase 2 (Linux CLI) — working. Collects the Epodonios subscription, drops dead configs via a parallel connectivity funnel, probes survivors against 5 traffic categories, ranks per category, and emits top-3 × 5. No server yet (Phase 3).

Verified run (this box, full 4,753 configs, --workers 8 --connect-timeout 2):

  • 4,753 supported configs (SSR dropped per ADR-004)
  • connectivity funnel: 57/4,753 connected, ~487s (8 workers is the bottleneck — raise --workers to ~32 to cut this to ~150s)
  • full per-category probe on the 57 candidates
  • emitted out/subscription.txt = 7–9 distinct configs, 3 per category, each named PS-<n><CATS] <host> (see "Subscription naming")
  • total wall-clock: ~921s at 8 workers

A smaller 800-config run at --workers 32 finished in ~243s with a 5-config subscription. Worker fan-out dominates cost at full scale, not per-probe time.

Layout

src/proxy_selector/
  config.py          config + subscription URL (env-overridable)
  collector.py       fetch + decode Epodonios subscription -> URIs (SSR dropped, ADR-004)
  uri_to_xray.py     URI -> xray outbound JSON (vmess/vless/trojan/tuic/ss)
  xray_runner.py     per-config xray launch + connectivity + full per-category probe
  categories.py      5 categories + provisional weights (ADR-003)
  ranking.py         per-category min-max normalize + gates + top-N (ADR-003)
  __main__.py        Phase 2 parallel funnel orchestrator
tools/xray           downloaded xray-core binary
docs/                DESIGN.md + ADRs

Setup (Linux)

uv sync                       # creates .venv, installs httpx[socks]
# xray binary (download once, or point --xray at it):
curl -sSL -o tools/xray.zip https://github.com/XTLS/Xray-core/releases/download/v26.3.27/Xray-linux-64.zip
unzip -o tools/xray.zip -d tools/ && chmod +x tools/xray

Run Phase 2

# probe N configs (parallel connectivity funnel), full-probe the best candidates,
# emit a subscription with top-3 per category
uv run python -m proxy_selector --limit 800 --workers 32 --budget 40 \
    --out out/subscription.txt
# import out/subscription.txt into v2rayNG as a normal subscription

Flags:

  • --limit N cap how many subscription configs to consider (default: all)
  • --workers N parallel xray worker count (default 8; 32 used in the run above)
  • --budget N max candidates to fully probe (default 40)
  • --xray PATH path to the xray binary (default: tools/xray)
  • --out PATH subscription output path (default: out/subscription.txt)
  • --connect-timeout S TCP/TLS connect timeout per config in seconds; dead configs fail fast (default 2.0)

Env: PROXY_SELECTOR_SUBSCRIPTION_URL overrides the source.

Subscription naming

Every emitted config is renamed so it is identifiable in v2rayNG. The display label (URI fragment #..., and vmess ps inside the base64 payload) is:

PS-<n><CATS] <host>
  • <n> — 1-based index in the emitted subscription (dedup order)
  • <CATS> — sorted tags of the categories this config won: T=Telegram, X=X, Y=YouTube, D=Developer, g=General
  • <host> — the config's server host (so the same host with different credentials shows twice, clearly)

A config that wins multiple categories keeps all its tags in one name, so overlaps are visible — e.g. PS-1TXYDg] 140.174.184.5 is one Shadowsocks config at 140.174.184.5 that won Telegram+X+YouTube+Developer+General. The ] is URL-encoded as %5D in the URI but v2rayNG decodes it on import.

Important environment caveats

  • System proxy: if HTTP_PROXY/HTTPS_PROXY/ALL_PROXY are set (e.g. a local v2rayNG/clash on 127.0.0.1:10808), the benchmark clients must bypass them — they talk to localhost xray and to the real destinations directly. The code uses trust_env=False on all measurement/localhost httpx clients; only the SOCKS measurement client pins its own proxy. Don't "fix" this by removing the bypass.
  • xray API is gRPC, not HTTP JSON-RPC. The earlier "one persistent xray, swap outbound via the runtime API" design does not work over httpx. The current model launches one short-lived xray per config (DESIGN §6) and fans them across the worker pool — simple and proven.
  • Secrets: Developer probes are reachability-only (no API keys sent). Never route authenticated traffic (GitHub tokens, LLM keys) through these anonymous proxies. See ADR-004.

Notes / limits

  • One xray process per config, parallelized across --workers (process startup is the dominant cost; fan-out hides it). Batching through one long-running instance would need xray's gRPC API — deferred (DESIGN §6).
  • Throughput is a 200KB speed sample (ranking only, not a bandwidth benchmark). The sample is capped at a 4s transfer budget so a free proxy that connects but throttles the download can't stall the candidate stage.
  • Weights in ranking.py are PROVISIONAL (ADR-003) — pending real run data.
  • SSR is dropped (ADR-004).
  • Free-config yield is low and churny; Phase 4's 30-min cache + explore/exploit cycle keeps winners fresh across runs.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages