from typing import Dict, Optional from pathlib import Path from urllib.parse import quote def _parse_proxy_line(line: str) -> Optional[str]: # Формат: scheme:ip:port[:login[:pass]] # Примеры: # socks5:127.0.0.1:9050 # socks5:127.0.0.1:9050:user:pass # http:127.0.0.1:8888 parts = [p.strip() for p in line.strip().split(":")] if len(parts) < 3: return None scheme, host, port = parts[0], parts[1], parts[2] user = parts[3] if len(parts) >= 4 and parts[3] else None password = parts[4] if len(parts) >= 5 and parts[4] else None auth = "" if user: auth = quote(user) if password: auth += f":{quote(password)}" auth += "@" # Исправление для socks5: httpx ожидает схему socks5:// (не socks://) if scheme == "socks": scheme = "socks5" # Явно проверяем протокол, чтобы был http://, https:// или socks5:// if not scheme.startswith(("http", "socks")): scheme = "http" return f"{scheme}://{auth}{host}:{port}" def _read_proxy_from_file() -> Optional[str]: file_path = Path("proxy.txt") if not file_path.exists(): return None try: for raw in file_path.read_text(encoding="utf-8").splitlines(): line = raw.strip() if not line or line.startswith("#"): continue url = _parse_proxy_line(line) if url: return url except Exception: return None return None def build_httpx_proxies() -> Optional[Dict[str, str]]: # Читаем только из proxy.txt (без переменных окружения) url = _read_proxy_from_file() if not url: return None # Для httpx корректнее указывать схемы явно return { "http://": url, "https://": url, }