"""HTTP client utilities for making requests to the backend API""" import aiohttp from typing import Optional import ssl import os def get_windows_host_ip() -> Optional[str]: """ Get the Windows host IP address when running in WSL. In WSL2, the Windows host IP is typically the first nameserver in /etc/resolv.conf. """ try: if os.path.exists("/etc/resolv.conf"): with open("/etc/resolv.conf", "r") as f: for line in f: if line.startswith("nameserver"): ip = line.split()[1] if ip not in ["127.0.0.1", "127.0.0.53"] and not ip.startswith("fe80"): return ip except Exception: pass return None def normalize_backend_url(url: str) -> str: """ Normalize backend URL for better compatibility, especially on WSL and Docker. """ if not ("localhost" in url or "127.0.0.1" in url): return url if os.path.exists("/.dockerenv"): print(f"Warning: Running in Docker but URL contains localhost: {url}") print("Please set BACKEND_URL environment variable in docker-compose.yml to use Docker service name (e.g., http://backend:8000/api/v1)") return url.replace("localhost", "127.0.0.1") try: if os.path.exists("/proc/version"): with open("/proc/version", "r") as f: version_content = f.read().lower() if "microsoft" in version_content: windows_ip = get_windows_host_ip() if windows_ip: if "localhost" in url or "127.0.0.1" in url: url = url.replace("localhost", windows_ip).replace("127.0.0.1", windows_ip) print(f"WSL detected: Using Windows host IP {windows_ip} for backend connection") return url except Exception as e: print(f"Warning: Could not detect WSL environment: {e}") if url.startswith("http://localhost") or url.startswith("https://localhost"): return url.replace("localhost", "127.0.0.1") return url def create_http_session(timeout: Optional[aiohttp.ClientTimeout] = None) -> aiohttp.ClientSession: """ Create a configured aiohttp ClientSession for backend API requests. Args: timeout: Optional timeout configuration. Defaults to 30 seconds total timeout. Returns: Configured aiohttp.ClientSession """ if timeout is None: timeout = aiohttp.ClientTimeout(total=30, connect=10) connector = aiohttp.TCPConnector( ssl=False, limit=100, limit_per_host=30, force_close=True, enable_cleanup_closed=True ) ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE return aiohttp.ClientSession( connector=connector, timeout=timeout, headers={ "Content-Type": "application/json", "Accept": "application/json" } )