From 587c72f4c3fa50d996fdddcc781bf777ae8ea766 Mon Sep 17 00:00:00 2001 From: SimplifiedPrivacy Date: Thu, 22 Oct 2026 13:37:27 -0400 Subject: [PATCH] async ip address calls --- .../networking/general_connection_tools/ip.py | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/core/services/networking/general_connection_tools/ip.py b/core/services/networking/general_connection_tools/ip.py index 807977b..41571df 100644 --- a/core/services/networking/general_connection_tools/ip.py +++ b/core/services/networking/general_connection_tools/ip.py @@ -11,6 +11,7 @@ from essentials.observers.ConnectionObserver import ConnectionObserver # generic import time import random +import asyncio import httpx from httpx_socks import AsyncProxyTransport import httpx_socks @@ -31,50 +32,63 @@ API_ENDPOINT_FORMATS = { MAX_ATTEMPTS = 3 def test(connection_observer: Optional[ConnectionObserver], port: Optional[int] = None) -> Result: - """ - Cycles through 3 possible endpoints, - to attempt to get an IP address for the systemwide connection. - """ - attempt = 0 - endpoint_index = 0 - endpoint_list = list(API_ENDPOINT_FORMATS.keys()) + return asyncio.run(_test(connection_observer, port)) + +async def _test(connection_observer: Optional[ConnectionObserver], port: Optional[int] = None) -> Result: + endpoint_list = list(API_ENDPOINT_FORMATS.keys())[:MAX_ATTEMPTS] + if port: - transport = httpx_socks.SyncProxyTransport( + transport = httpx_socks.AsyncProxyTransport( proxy_type=ProxyType.SOCKS5, proxy_host="127.0.0.1", proxy_port=port, ) - _ip_test_client = httpx.Client(transport=transport, http2=True, timeout=6) + client = httpx.AsyncClient(transport=transport, http2=True, timeout=6) else: - _ip_test_client = httpx.Client(http2=True, timeout=6) + client = httpx.AsyncClient(http2=True, timeout=6) - - while attempt < MAX_ATTEMPTS: - endpoint_url = endpoint_list[attempt] - attempt += 1 - logger.info(f"Attempt {attempt}: Trying {endpoint_url}") + async def attempt_request(url: str, index: int): + logger.info(f"Attempt {index + 1}: Trying {url}") if connection_observer: - connection_observer.notify("connecting", f"Testing IP. Attempt {attempt}") + connection_observer.notify("connecting", f"Testing IP. Attempt {index + 1}") + try: - raw_response = _ip_test_client.get(endpoint_url) - + raw_response = await client.get(url) filtered_response = classify_response(raw_response) if filtered_response.valid: ip_address = extract_ip_from_response( response=filtered_response.data, - api_url=endpoint_url + api_url=url ) if ip_address is not None: return Result(valid=True, data=ip_address) - else: - logger.error(f"Skipping {endpoint_url}") - + + logger.error(f"Skipping {url}") except Exception as e: - logger.error(f"We are NOT error handling this. Skipping {endpoint_url}. Invalid API reply or failed connection {str(e)}") + logger.error(f"Skipping {url}. Invalid API reply or failed connection {str(e)}") + + return Result(valid=False) - logger.error(f"We went through {MAX_ATTEMPTS} attempts and could not get a reply.") + try: + # Create tasks for all endpoints to run them concurrently + tasks = [asyncio.create_task(attempt_request(url, i)) for i, url in enumerate(endpoint_list)] + + # Process tasks as they complete + for future in asyncio.as_completed(tasks): + result = await future + if result.valid: + # Cancel all other pending tasks immediately + for t in tasks: + if not t.done(): + t.cancel() + return result + + finally: + await client.aclose() + + logger.error(f"We went through {len(endpoint_list)} attempts and could not get a reply.") return Result(valid=False, error_type=ResultError.CONNECTION, message="Could not connect.") @@ -84,9 +98,6 @@ def extract_ip_from_response(response: dict, api_url: str) -> str | bool: Extract the IP address from the API's response, based on which keys that API uses. - Rank: - Helper - On Success: Returns String of IP address