
    <0j~                    T    d Z ddlmZ ddlZ	 ddlZn# e$ r dZY nw xY wdZdZd	dZdS )
u(  Shared HTTP client factory for long-lived platform adapters.

Gateway messaging platforms (QQ Bot, Feishu, WeCom, DingTalk, Signal,
BlueBubbles, WeCom-callback) keep a persistent ``httpx.AsyncClient``
alive for the adapter's lifetime.  That amortises TLS/connection setup
across many API calls, but it also means the process's file-descriptor
pressure is sensitive to how aggressively the pool recycles idle keep-
alive connections.

httpx's default ``keepalive_expiry`` is 5 seconds.  On macOS behind
Cloudflare Warp (and other transparent proxies), peer-initiated FIN can
sit in ``CLOSE_WAIT`` longer than that before the local socket actually
drains — which, multiplied across 7 long-lived adapters plus the LLM
client and MCP clients, walks straight into the default 256 fd limit.
See #18451.

``platform_httpx_limits()`` returns a tighter ``httpx.Limits`` the
adapter factories use instead of the httpx default.  The values chosen:

* ``max_keepalive_connections=10`` — plenty for any single adapter;
  platform APIs rarely parallelise beyond this.
* ``keepalive_expiry=2.0`` — close idle sockets aggressively so a
  proxy's lingering CLOSE_WAIT window can't starve the process.

Override via ``HERMES_GATEWAY_HTTPX_KEEPALIVE_EXPIRY`` /
``HERMES_GATEWAY_HTTPX_MAX_KEEPALIVE`` env vars when tuning under load.
    )annotationsNg       @
   return'httpx.Limits | None'c                     t           dS dd} dd	} | d
t                    } |dt                    }t          j        ||          S )zReturn ``httpx.Limits`` tuned for persistent platform-adapter clients.

    Returns ``None`` when httpx isn't importable, so callers can fall
    back to httpx's built-in default without a hard dependency on this
    helper being reachable.
    Nnamestrdefaultfloatr   c                    t           j                            | d                                          }|s|S 	 t	          |          }n# t
          t          f$ r |cY S w xY w|dk    r|n|S N r   )osenvirongetstripr   	TypeError
ValueErrorr   r
   rawvals       K/home/rurouni/.hermes/hermes-agent/gateway/platforms/_http_client_limits.py
_env_floatz)platform_httpx_limits.<locals>._env_float5   s}    jnnT2&&,,.. 	N	**CC:& 	 	 	NNN	Aggss7*   A AAintc                    t           j                            | d                                          }|s|S 	 t	          |          }n# t
          t          f$ r |cY S w xY w|dk    r|n|S r   )r   r   r   r   r   r   r   r   s       r   _env_intz'platform_httpx_limits.<locals>._env_int?   s}    jnnT2&&,,.. 	N	c((CC:& 	 	 	NNN	Aggss7*r   %HERMES_GATEWAY_HTTPX_KEEPALIVE_EXPIRY"HERMES_GATEWAY_HTTPX_MAX_KEEPALIVE)max_keepalive_connectionskeepalive_expiry)r   r	   r
   r   r   r   )r   r	   r
   r   r   r   )httpx_DEFAULT_KEEPALIVE_EXPIRY_S_DEFAULT_MAX_KEEPALIVELimits)r   r   r!   max_keepalives       r   platform_httpx_limitsr'   +   s     }t+ + + ++ + + + "z/1L  H,.D M <"/)       )r   r   )	__doc__
__future__r   r   r"   ImportErrorr#   r$   r'    r(   r   <module>r-      s    8 # " " " " " 				LLLL   EEE "  ) ) ) ) ) )s    