|
| 1 | +""" |
| 2 | +HTTP Client Factory with Proxy Support |
| 3 | +
|
| 4 | +This module provides a centralized way to create httpx.AsyncClient instances |
| 5 | +with proxy configuration support. All external API calls should use this |
| 6 | +factory to ensure consistent proxy usage across the application. |
| 7 | +""" |
| 8 | + |
| 9 | +import httpx |
| 10 | +from typing import Optional, Dict, Any |
| 11 | +from loguru import logger |
| 12 | +from app.core.config import PROXY_HOST, PROXY_PORT |
| 13 | + |
| 14 | + |
| 15 | +def get_proxy_config() -> Optional[str]: |
| 16 | + """ |
| 17 | + Get the proxy configuration string if proxy is configured. |
| 18 | + |
| 19 | + Returns: |
| 20 | + str: Proxy URL in format "http://host:port" or None if not configured |
| 21 | + """ |
| 22 | + if PROXY_HOST and PROXY_PORT: |
| 23 | + proxy_url = f"http://{PROXY_HOST}:{PROXY_PORT}" |
| 24 | + logger.debug(f"Using proxy configuration: {proxy_url}") |
| 25 | + return proxy_url |
| 26 | + return None |
| 27 | + |
| 28 | + |
| 29 | +def create_http_client( |
| 30 | + timeout: Optional[float] = None, |
| 31 | + proxies: Optional[Dict[str, str]] = None, |
| 32 | + **kwargs: Any |
| 33 | +) -> httpx.AsyncClient: |
| 34 | + """ |
| 35 | + Create an httpx.AsyncClient with proxy support. |
| 36 | + |
| 37 | + Args: |
| 38 | + timeout: Request timeout in seconds |
| 39 | + proxies: Custom proxy configuration (overrides global proxy) |
| 40 | + **kwargs: Additional arguments to pass to httpx.AsyncClient |
| 41 | + |
| 42 | + Returns: |
| 43 | + httpx.AsyncClient: Configured HTTP client instance |
| 44 | + """ |
| 45 | + # Use custom proxies if provided, otherwise use global proxy config |
| 46 | + if proxies is None: |
| 47 | + proxy_url = get_proxy_config() |
| 48 | + if proxy_url: |
| 49 | + proxies = { |
| 50 | + "http://": proxy_url, |
| 51 | + "https://": proxy_url |
| 52 | + } |
| 53 | + |
| 54 | + # Set default timeout if not provided |
| 55 | + if timeout is None: |
| 56 | + timeout = 30.0 |
| 57 | + |
| 58 | + client_kwargs = { |
| 59 | + "timeout": timeout, |
| 60 | + **kwargs |
| 61 | + } |
| 62 | + |
| 63 | + # Add proxy configuration if available |
| 64 | + if proxies: |
| 65 | + # In httpx 0.28+, use 'proxy' parameter with a single URL |
| 66 | + proxy_url = proxies.get("https://") or proxies.get("http://") |
| 67 | + if proxy_url: |
| 68 | + client_kwargs["proxy"] = proxy_url |
| 69 | + logger.debug(f"Creating HTTP client with proxy: {proxy_url}") |
| 70 | + else: |
| 71 | + logger.debug("Creating HTTP client without proxy") |
| 72 | + else: |
| 73 | + logger.debug("Creating HTTP client without proxy") |
| 74 | + |
| 75 | + return httpx.AsyncClient(**client_kwargs) |
| 76 | + |
| 77 | + |
| 78 | +async def make_request( |
| 79 | + method: str, |
| 80 | + url: str, |
| 81 | + timeout: Optional[float] = None, |
| 82 | + proxies: Optional[Dict[str, str]] = None, |
| 83 | + **kwargs: Any |
| 84 | +) -> httpx.Response: |
| 85 | + """ |
| 86 | + Make a single HTTP request with proxy support. |
| 87 | + |
| 88 | + Args: |
| 89 | + method: HTTP method (GET, POST, PUT, DELETE, etc.) |
| 90 | + url: Request URL |
| 91 | + timeout: Request timeout in seconds |
| 92 | + proxies: Custom proxy configuration |
| 93 | + **kwargs: Additional arguments to pass to the request |
| 94 | + |
| 95 | + Returns: |
| 96 | + httpx.Response: HTTP response |
| 97 | + """ |
| 98 | + async with create_http_client(timeout=timeout, proxies=proxies) as client: |
| 99 | + response = await client.request(method, url, **kwargs) |
| 100 | + return response |
| 101 | + |
| 102 | + |
| 103 | +# Convenience functions for common HTTP methods |
| 104 | +async def get(url: str, **kwargs: Any) -> httpx.Response: |
| 105 | + """Make a GET request with proxy support.""" |
| 106 | + return await make_request("GET", url, **kwargs) |
| 107 | + |
| 108 | + |
| 109 | +async def post(url: str, **kwargs: Any) -> httpx.Response: |
| 110 | + """Make a POST request with proxy support.""" |
| 111 | + return await make_request("POST", url, **kwargs) |
| 112 | + |
| 113 | + |
| 114 | +async def put(url: str, **kwargs: Any) -> httpx.Response: |
| 115 | + """Make a PUT request with proxy support.""" |
| 116 | + return await make_request("PUT", url, **kwargs) |
| 117 | + |
| 118 | + |
| 119 | +async def delete(url: str, **kwargs: Any) -> httpx.Response: |
| 120 | + """Make a DELETE request with proxy support.""" |
| 121 | + return await make_request("DELETE", url, **kwargs) |
| 122 | + |
| 123 | + |
| 124 | +async def patch(url: str, **kwargs: Any) -> httpx.Response: |
| 125 | + """Make a PATCH request with proxy support.""" |
| 126 | + return await make_request("PATCH", url, **kwargs) |
0 commit comments