
    i]$                    "   U d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	 ddl
Z
 ej        e          ZdZdZdedd	i d
dedd	ddid
gZded<   dgZded<   d.d/dZ G d de
j                  Zd0dZd1dZd2dZd3d#Zd4d$Zd5d)Zd6d-ZdS )7aY  Telegram-specific network helpers.

Provides a hostname-preserving fallback transport for networks where
api.telegram.org resolves to an endpoint that is unreachable from the current
host. The transport keeps the logical request host and TLS SNI as
api.telegram.org while retrying the TCP connection against one or more fallback
IPv4 addresses.
    )annotationsN)IterableOptionalzapi.telegram.orgg      @zhttps://dns.google/resolveA)nametype)urlparamsheadersz$https://cloudflare-dns.com/dns-queryAcceptzapplication/dns-jsonz
list[dict]_DOH_PROVIDERSz149.154.167.220	list[str]_SEED_FALLBACK_IPSreturn
str | Nonec                (    ddl m}  |d|           S )Nr   )resolve_proxy_urlTELEGRAM_PROXYtarget_hosts)gateway.platforms.baser   )r   r   s     G/home/ubuntu/.hermes/hermes-agent/gateway/platforms/telegram_network.py_resolve_proxy_urlr   .   s+    888888-LIIII    c                  *    e Zd ZdZddZdd	ZddZdS )TelegramFallbackTransportad  Retry Telegram Bot API requests via fallback IPs while preserving TLS/SNI.

    Requests continue to target https://api.telegram.org/... logically, but on
    connect failures the underlying TCP connection is retried against a known
    reachable IP. This is effectively the programmatic equivalent of
    ``curl --resolve api.telegram.org:443:<ip>``.
    fallback_ipsIterable[str]c                ^   d t                               t          |                    D             | _        t	          t
          g| j                  }|r	dvr|d<   t          j        di | _        fd| j        D             | _	        d | _
        t          j                    | _        d S )Nc                    g | ]}|S  r!   ).0ips     r   
<listcomp>z6TelegramFallbackTransport.__init__.<locals>.<listcomp>>   s    ```Rb```r   r   proxyc                4    i | ]}|t          j        d i S )r!   )httpxAsyncHTTPTransport)r"   r#   transport_kwargss     r   
<dictcomp>z6TelegramFallbackTransport.__init__.<locals>.<dictcomp>C   s:     
 
 
ACB(<<+;<<
 
 
r   r!   )dictfromkeys_normalize_fallback_ips_fallback_ipsr   _TELEGRAM_API_HOSTr'   r(   _primary
_fallbacks
_sticky_ipasyncioLock_sticky_lock)selfr   r)   	proxy_urls     ` r   __init__z"TelegramFallbackTransport.__init__=   s    ``4==9PQ]9^9^+_+_```&5G4]$J\4]^^^	 	2(888(1W%0DD3CDD
 
 
 
GKGY
 
 
 *.#LNNr   requesthttpx.Requestr   httpx.Responsec           	       K   |j         j        t          k    s| j        s | j                            |           d {V S | j        }|r|gnd g}| j        D ]}||k    r|                    |           d }|D ]8}||nt          ||          }|| j        n| j	        |         }	 |                    |           d {V }|i| j        |k    r^| j
        4 d {V  | j        |k    r"|| _        t                              d|           d d d           d {V  n# 1 d {V swxY w Y   |c S # t          $ ru}	|	}t          |	          s |:t                              d|	d                    | j                             Y d }	~	t                              d||	           Y d }	~	2d }	~	ww xY w|t!          d          |)NzQ[Telegram] Primary api.telegram.org path unreachable; using sticky fallback IP %szR[Telegram] Primary api.telegram.org connection failed (%s); trying fallback IPs %s, z$[Telegram] Fallback IP %s failed: %sz=All Telegram fallback IPs exhausted but no error was recorded)r	   hostr/   r.   r0   handle_async_requestr2   append_rewrite_request_for_ipr1   r5   loggerwarning	Exception_is_retryable_connect_errorjoinRuntimeError)
r6   r9   	sticky_ipattempt_orderr#   
last_error	candidate	transportresponseexcs
             r   r?   z.TelegramFallbackTransport.handle_async_requestI   s     ;1119K1;;GDDDDDDDDDO	<E-Qi[[D6$ 	) 	)BY$$R((('+
 	 	B#%:3J7TV3W3WI)+9LI!*!?!?	!J!JJJJJJJ>do&;&;#0        ?b00.0DO"NN s "                                  
2377 :NNl		$"455  
 HHHHEr3OOO ^___sC   %5D/.DD/
D$	$D/'D$	(D//
F.9AF)F))F.Nonec                   K   | j                                          d {V  | j                                        D ]}|                                 d {V  d S N)r0   acloser1   values)r6   rL   s     r   rR   z TelegramFallbackTransport.acloset   sz      m""$$$$$$$$$//11 	% 	%I""$$$$$$$$$$	% 	%r   N)r   r   )r9   r:   r   r;   )r   rO   )__name__
__module____qualname____doc__r8   r?   rR   r!   r   r   r   r   4   s[         
+ 
+ 
+ 
+) ) ) )V% % % % % %r   r   rS   r   c                   g }| D ]}t          |                                          }|s&	 t          j        |          }n+# t          $ r t
                              d|           Y cw xY w|j        dk    rt
                              d|           |j        s|j	        s|j
        s|j        rt
                              d|           |                    t          |                     |S )Nz)Ignoring invalid Telegram fallback IP: %r   z*Ignoring non-IPv4 Telegram fallback IP: %sz2Ignoring private/internal Telegram fallback IP: %s)strstrip	ipaddress
ip_address
ValueErrorrB   rC   version
is_privateis_loopbackis_link_localis_unspecifiedr@   )rS   
normalizedvaluerawaddrs        r   r-   r-   z   s   J % %%jj   		',,DD 	 	 	NNFLLLH	 <1NNGMMM? 	d. 	$2D 	H[ 	NNOQTUUU#d))$$$$s   A%A)(A)re   c                f    | sg S d |                      d          D             }t          |          S )Nc                6    g | ]}|                                 S r!   )r[   )r"   parts     r   r$   z)parse_fallback_ip_env.<locals>.<listcomp>   s     777dTZZ\\777r   ,)splitr-   )re   partss     r   parse_fallback_ip_envrn      s<     	77ekk#&6&6777E"5)))r   set[str]c                     	 t          j        t          dt           j                  } d | D             S # t          $ r t                      cY S w xY w)zJReturn the IPv4 addresses that the OS resolver gives for api.telegram.org.i  c                *    h | ]}|d          d         S )rY   r   r!   )r"   rg   s     r   	<setcomp>z&_resolve_system_dns.<locals>.<setcomp>   s     ///tQ
///r   )socketgetaddrinfor/   AF_INETrD   set)resultss    r   _resolve_system_dnsrx      sZ    $%7fnMM//w////   uus   03 AAclienthttpx.AsyncClientproviderr+   c                `  K   	 |                      |d         |d         |d                    d{V }|                                 |                                }g }|                     dg           D ]~}|                     d          dk    r|                     d	d
                                          }	 t	          j        |           |                    |           o# t          $ r Y {w xY w|S # t          $ r.}t          
                    d|d         |           g cY d}~S d}~ww xY w)z/Query one DoH provider and return A-record IPs.r	   r
   r   )r
   r   NAnswerr      data zDoH query to %s failed: %s)getraise_for_statusjsonr[   r\   r]   r@   r^   rD   rB   debug)ry   r{   respr   ipsanswerrf   rN   s           r   _query_doh_providerr      sg     ZZUOHX$6@S   
 
 
 
 
 
 
 
 	yy{{hhx,, 	 	Fzz&!!Q&&**VR((..00C$S)))

3   
   18E?CHHH						sB   B4C5 9)C#"C5 #
C0-C5 /C00C5 5
D-?#D("D-(D-c                   
K   t          j        t          j        t                              4 d{V 

fdt          D             } t          j        t                    }t          j        |g| R ddi d{V }ddd          d{V  n# 1 d{V swxY w Y   t          |d         t                    r|d         nt                      }g }|dd         D ],}t          |t                    r|                    |           -t                      }g }|D ]4}||vr.||vr*|                    |           |                    |           5t          |          }	|	r0t                               dd	                    |	                     |	S t                               d
d	                    |          pdd	                    t(                               t          t(                    S )a<  Auto-discover Telegram API IPs via DNS-over-HTTPS.

    Resolves api.telegram.org through Google and Cloudflare DoH, collects all
    unique IPs, and excludes the system-DNS-resolved IP (which is presumably
    unreachable on this network).  Falls back to a hardcoded seed list when DoH
    is also unavailable.
    )timeoutNc                0    g | ]}t          |          S r!   )r   )r"   pry   s     r   r$   z)discover_fallback_ips.<locals>.<listcomp>   s$    LLL(33LLLr   return_exceptionsTr   r~   z,Discovered Telegram fallback IPs via DoH: %sr=   zMDoH discovery yielded no new IPs (system DNS: %s); using seed fallback IPs %sunknown)r'   AsyncClientTimeout_DOH_TIMEOUTr   r3   	to_threadrx   gather
isinstancerv   listextendaddr@   r-   rB   r   rF   infor   )	doh_taskssystem_dns_taskrw   
system_ipsdoh_ipsrseen
candidatesr#   	validatedry   s             @r   discover_fallback_ipsr      s       |)D)DEEE \ \ \ \ \ \ \LLLL^LLL	!+,?@@[[[[VZ[[[[[[[[\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ *4GAJ)D)DO71::#%%JGQRR[  a 	NN1 UUDJ " "T>>b
22HHRLLLb!!! (
33I CTYYyEYEYZZZ
KKW		**		$%%  
 "###s   AB
BBr9   r:   r#   rZ   c                   | j         j        pt          }| j                             |          }| j                                        }||d<   t          | j                  }||d<   t          j	        | j
        ||| j        |          S )N)r>   r>   sni_hostname)methodr	   r   stream
extensions)r	   r>   r/   	copy_withr   copyr+   r   r'   Requestr   r   )r9   r#   original_hostr	   r   r   s         r   rA   rA      s    K$:(:M
+

R

(
(Co""$$G#GFOg())J!.J~=~~   r   rN   rD   boolc                N    t          | t          j        t          j        f          S rQ   )r   r'   ConnectTimeoutConnectError)rN   s    r   rE   rE      s    cE0%2DEFFFr   rQ   )r   r   )rS   r   r   r   )re   r   r   r   )r   ro   )ry   rz   r{   r+   r   r   )r   r   )r9   r:   r#   rZ   r   r:   )rN   rD   r   r   )rW   
__future__r   r3   r\   loggingrs   typingr   r   r'   	getLoggerrT   rB   r/   r   r   __annotations__r   r   AsyncBaseTransportr   r-   rn   rx   r   r   rA   rE   r!   r   r   <module>r      s     # " " " " "        % % % % % % % % 		8	$	$'   ,-s;;  6-s;;45      "3 3  3 3 3 3J J J J JC% C% C% C% C% 8 C% C% C%L   ** * * *      4)$ )$ )$ )$X    G G G G G Gr   