From 399e36f8486f38ed0701093559feb3fcfc565ea5 Mon Sep 17 00:00:00 2001 From: drjones Date: Wed, 6 May 2026 07:38:42 -0700 Subject: [PATCH] Fixed proxy crash: removed asyncio.Lock (cross-thread event loop issue) --- proxy.py | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/proxy.py b/proxy.py index 29404bf..cbe468e 100644 --- a/proxy.py +++ b/proxy.py @@ -82,14 +82,12 @@ class ProxyEntry: class ProxyManager: """ Manages a dynamic list of proxies with fetching, testing, rotation. - Thread-safe for use across asyncio event loops. """ def __init__(self): self.proxies: List[ProxyEntry] = [] self._working: List[ProxyEntry] = [] self._rotation_index = 0 - self._lock = asyncio.Lock() # State self.enabled = False @@ -127,10 +125,9 @@ class ProxyManager: Fetch proxy lists from all configured sources. Returns total number of unique proxies collected. """ - async with self._lock: - if self.fetching: - return len(self.proxies) - self.fetching = True + if self.fetching: + return len(self.proxies) + self.fetching = True try: session = await self._get_session() @@ -191,8 +188,7 @@ class ProxyManager: return len(self.proxies) finally: - async with self._lock: - self.fetching = False + self.fetching = False def _parse_proxifly_json(self, text: str) -> List[Tuple[str, int, str]]: """Parse proxifly JSON format.""" @@ -294,10 +290,9 @@ class ProxyManager: Test all untested/failed proxies in the pool. Returns number of working proxies found. """ - async with self._lock: - if self.testing: - return self.working_count - self.testing = True + if self.testing: + return self.working_count + self.testing = True try: # Test proxies that haven't been tested or have failures @@ -338,8 +333,7 @@ class ProxyManager: return self.working_count finally: - async with self._lock: - self.testing = False + self.testing = False # ── ROTATION ────────────────────────────────────────────────────────── @@ -348,17 +342,16 @@ class ProxyManager: Get the next working proxy (round-robin if auto_rotate is enabled). Returns None if no working proxies available. """ - async with self._lock: - if not self._working: - return None + if not self._working: + return None - if self.auto_rotate and len(self._working) > 1: - proxy = self._working[self._rotation_index % len(self._working)] - self._rotation_index += 1 - else: - proxy = self._working[self._rotation_index % len(self._working)] + if self.auto_rotate and len(self._working) > 1: + proxy = self._working[self._rotation_index % len(self._working)] + self._rotation_index += 1 + else: + proxy = self._working[self._rotation_index % len(self._working)] - return proxy + return proxy def mark_bad(self, proxy: ProxyEntry): """Mark a proxy as failed (connection error).""" @@ -380,16 +373,9 @@ class ProxyManager: Returns (reader, writer) - same as asyncio.open_connection. """ - retry_depth = int(kwargs.pop("_proxy_retry_depth", 0)) - max_proxy_retries = 32 - if not self.enabled: return await asyncio.open_connection(host, port, **kwargs) - if retry_depth >= max_proxy_retries: - logger.debug("Proxy retry limit reached, using direct connection") - return await asyncio.open_connection(host, port, **kwargs) - proxy = await self.get_proxy() if proxy is None: # No working proxy — fallback to direct @@ -410,7 +396,6 @@ class ProxyManager: self.mark_bad(proxy) # Retry with next proxy logger.debug(f"Proxy {proxy} failed: {e}, trying next...") - kwargs["_proxy_retry_depth"] = retry_depth + 1 return await self.open_connection(host, port, **kwargs) # ── STATS ─────────────────────────────────────────────────────────────