Download proxy_client.py from ItsBounvy/bot_host: direct link, hf CLI and curl.
- Browser
- Download file 4.66 kB
-
https://huggingface.co/spaces/ItsBounvy/bot_host/resolve/main/proxy_client.py
- Command line
-
hf download hf://spaces/ItsBounvy/bot_host/proxy_client.py
-
curl -L -o proxy_client.py https://huggingface.co/spaces/ItsBounvy/bot_host/resolve/main/proxy_client.py
4.66 kB
| """Panel-side wrapper that routes outbound HTTP through the Render proxy. | |
| Why | |
| --- | |
| HuggingFace Spaces share outbound IPs that several big services | |
| (Telegram Bot API, OpenAI, Anthropic, etc.) routinely blacklist. The | |
| panel itself sits on a HF Space — to call those APIs reliably we | |
| relay through the small service in ``render_proxy/``. | |
| Strategy | |
| -------- | |
| If ``RENDER_PROXY_URL`` + ``RENDER_PROXY_TOKEN`` are configured we | |
| transparently rewrite the host of outgoing requests: | |
| * the panel still builds normal URLs (``https://api.telegram.org/...``), | |
| * we intercept just before sending and rewrite the call to go through | |
| ``https://<proxy>/forward?target=<encoded original URL>`` with a | |
| bearer token. Response is returned to the caller as if direct. | |
| For per-bot calls, the bot itself uses the values from env vars | |
| ``LLM_PROXY_URL`` / ``TELEGRAM_PROXY_URL`` (set by the panel during | |
| deploy). | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| from typing import Any, Optional | |
| import httpx | |
| from config import PANEL_CONFIG | |
| log = logging.getLogger("panel.proxy-client") | |
| def render_proxy_enabled() -> bool: | |
| return bool(PANEL_CONFIG.render_proxy_url and PANEL_CONFIG.render_proxy_token) | |
| def _rewrite_via_proxy(url: str) -> str: | |
| """Return ``url`` rewritten through the proxy's /forward endpoint.""" | |
| from urllib.parse import quote | |
| proxy = PANEL_CONFIG.render_proxy_url.rstrip("/") | |
| return f"{proxy}/forward?target={quote(url, safe='')}" | |
| def _auth_headers() -> dict: | |
| return {"Authorization": f"Bearer {PANEL_CONFIG.render_proxy_token}"} | |
| def proxy_aware_request( | |
| method: str, | |
| url: str, | |
| *, | |
| headers: Optional[dict] = None, | |
| json: Any = None, | |
| data: Any = None, | |
| params: Optional[dict] = None, | |
| timeout: float = 60.0, | |
| follow_redirects: bool = True, | |
| ) -> httpx.Response: | |
| """Make an HTTP request, routed through the Render proxy when set. | |
| The caller passes a real external URL. If the proxy is enabled | |
| the URL is rewritten; the request body and headers are otherwise | |
| identical to a direct call. Caller receives a normal | |
| ``httpx.Response`` and can ``.raise_for_status()`` / ``.json()`` | |
| just like usual. | |
| """ | |
| headers = dict(headers or {}) | |
| # When proxying, we drop the original Host header — the upstream | |
| # is the proxy. httpx sets Host from the URL automatically. | |
| target = _rewrite_via_proxy(url) if render_proxy_enabled() else url | |
| if render_proxy_enabled(): | |
| # Carry the original target host in a header so the proxy | |
| # can log which logical backend was hit (useful in Render logs). | |
| from urllib.parse import urlparse | |
| original_host = urlparse(url).hostname or "" | |
| headers.setdefault("X-Panel-Original-Host", original_host) | |
| headers.update(_auth_headers()) | |
| return httpx.request( | |
| method=method, | |
| url=target, | |
| headers=headers, | |
| json=json, | |
| data=data, | |
| params=params, | |
| timeout=timeout, | |
| follow_redirects=follow_redirects, | |
| ) | |
| async def proxy_aware_async_request( | |
| method: str, | |
| url: str, | |
| *, | |
| headers: Optional[dict] = None, | |
| json: Any = None, | |
| data: Any = None, | |
| params: Optional[dict] = None, | |
| timeout: float = 60.0, | |
| follow_redirects: bool = True, | |
| ) -> httpx.Response: | |
| """Async variant of :func:`proxy_aware_request`.""" | |
| headers = dict(headers or {}) | |
| target = _rewrite_via_proxy(url) if render_proxy_enabled() else url | |
| if render_proxy_enabled(): | |
| from urllib.parse import urlparse | |
| headers.setdefault("X-Panel-Original-Host", urlparse(url).hostname or "") | |
| headers.update(_auth_headers()) | |
| async with httpx.AsyncClient(timeout=timeout, follow_redirects=follow_redirects) as client: | |
| return await client.request( | |
| method=method, | |
| url=target, | |
| headers=headers, | |
| json=json, | |
| data=data, | |
| params=params, | |
| ) | |
| def bot_env_extras() -> dict[str, str]: | |
| """Return the env-var dict the panel should write into each | |
| bot's ``.env`` file when ``RENDER_PROXY_URL`` is set. | |
| The bot uses ``TELEGRAM_PROXY_URL`` and ``LLM_PROXY_URL`` to call | |
| the proxy instead of Telegram/LLM providers directly. | |
| """ | |
| if not render_proxy_enabled(): | |
| return {} | |
| proxy = PANEL_CONFIG.render_proxy_url.rstrip("/") | |
| return { | |
| "RENDER_PROXY_URL": PANEL_CONFIG.render_proxy_url, | |
| "RENDER_PROXY_TOKEN": PANEL_CONFIG.render_proxy_token, | |
| "TELEGRAM_PROXY_URL": f"{proxy}/telegram", | |
| "LLM_PROXY_URL": f"{proxy}/llm/openai", # sensible default | |
| } |