U
    ¯ªh!?  ã                   @   sÀ   d dl Z d dlZd dlZd dlZzd dlZW n ek
rD   dZY nX zd dlZW n ek
rj   dZY nX ddlm	Z	m
Z
 ddlmZ G dd„ de jƒZG dd„ deƒZG d	d
„ d
e jƒZdS )é    Né   )ÚInvalidChecksumErrorÚInvalidBufferError)Úhelpersc                   @   s¤   e Zd ZdZdZdddœdd„Zedd„ ƒZed#d	d
„ƒZd$dd„Z	d%dd„Z
d&dd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ ZdS )'Ú
Connectionaì  
    The `Connection` class is a wrapper around ``asyncio.open_connection``.

    Subclasses will implement different transport modes as atomic operations,
    which this class eases doing since the exposed interface simply puts and
    gets complete data payloads to and from queues.

    The only error that will raise from send and receive methods is
    ``ConnectionError``, which will raise when attempting to send if
    the client is disconnected (includes remote disconnections).
    N)ÚproxyÚ
local_addrc                C   sn   || _ || _|| _|t | _|| _|| _d | _d | _d| _	d | _
d | _d | _d | _t d¡| _t d¡| _d S )NFé   )Ú_ipÚ_portZ_dc_idÚ__name__Ú_logÚ_proxyÚ_local_addrÚ_readerÚ_writerÚ
_connectedÚ
_send_taskÚ
_recv_taskÚ_codecÚ_obfuscationÚasyncioÚQueueÚ_send_queueÚ_recv_queue)ÚselfÚipÚportZdc_idÚloggersr   r   © r   úJ/tmp/pip-unpacked-wheel-c81u5j2r/telethon/network/connection/connection.pyÚ__init__$   s    
zConnection.__init__c                 C   s$   t d krtdƒ‚t j| dt jddS )NzICannot use proxy that requires SSL without the SSL module being availableTzADH-AES256-SHA)Údo_handshake_on_connectÚssl_versionÚciphers)Ússl_modÚRuntimeErrorÚwrap_socketÚPROTOCOL_SSLv23©Úsockr   r   r    Ú_wrap_socket_ssl5   s    ÿüzConnection._wrap_socket_sslTc                 C   s  t | tƒr|  ¡ } tr¦ddlm} | |jks<| dks<| dkrD|j}nR| |jks^| dks^| dkrf|j}n0| |jks€| dks€| dkrˆ|j}ntd	 	| ¡ƒ‚||||||fS dd
l
m}m}	m}
 | dksÊ| dkrÐ|}n:| dksà| dkræ|	}n$| dksö| dkrü|
}ntd	 	| ¡ƒ‚||||||fS d S )Nr   )Ú	ProxyTypeé   Zsocks5r	   Zsocks4r   ÚhttpzUnknown proxy protocol type: {})ÚSOCKS5ÚSOCKS4ÚHTTP)Ú
isinstanceÚstrÚlowerÚpython_socksr,   r/   r0   r1   Ú
ValueErrorÚformatÚsocks)Ú
proxy_typeÚaddrr   ZrdnsÚusernameÚpasswordr,   Úprotocolr/   r0   r1   r   r   r    Ú_parse_proxyC   s*    
zConnection._parse_proxyc                 Ã   sú  t | jttfƒr| j| jŽ }n0t | jtƒr:| jf | jŽ}ntd t| jƒ¡ƒ‚t	rPG dd„ dt
ƒ}|t	j_t
t	j_t
t	j_ddlm} |j|Ž }|d kr¶|j| j| j|dI d H }n˜d|jkrÚtj|j|jddf }}	ntj|j|jf }}	t |tj¡}| d¡ | |¡ tjt  ¡ j!||	d	|d
I d H  |j| j| j||dI d H }n¦dd l"}
d|d kr€tj| j| jddf }}	ntj| j| jf }}	|
 #|tj¡}|j$|Ž  | %|¡ |d k	rÊ| |¡ tjt  ¡ j!||	d	|d
I d H  | d¡ |S )NzProxy of unknown format: {}c                       s   e Zd Zd‡ fdd„	Z‡  ZS )z7Connection._proxy_connect.<locals>.ConnectionErrorExtraNc                    s   t ƒ  |¡ || _d S ©N)Úsuperr!   Ú
error_code)r   ÚmessagerA   ©Ú	__class__r   r    r!   {   s    z@Connection._proxy_connect.<locals>.ConnectionErrorExtra.__init__)N)r   Ú
__module__Ú__qualname__r!   Ú__classcell__r   r   rC   r    ÚConnectionErrorExtraz   s   rH   r   )ÚProxy)Ú	dest_hostÚ	dest_portÚtimeoutú:F)r*   Úaddress©rL   )rJ   rK   rL   Ú_socketr	   )&r2   r   ÚtupleÚlistr>   ÚdictÚ	TypeErrorr7   Útyper5   ÚConnectionErrorÚ_errorsÚ
ProxyErrorZProxyConnectionErrorZProxyTimeoutErrorZpython_socks.async_.asynciorI   ÚcreateÚconnectr
   r   Z
proxy_hostÚsocketÚAF_INET6Z
proxy_portÚAF_INETÚSOCK_STREAMÚsetblockingÚbindr   Úwait_forr   Úget_running_loopZsock_connectr8   Z
socksocketÚ	set_proxyÚ
settimeout)r   rL   r   ÚparsedrH   rI   r   r*   ÚmoderN   r8   r   r   r    Ú_proxy_connectj   sb    
ý


þü



þ
zConnection._proxy_connectc                 Ã   sô   | j d k	rVt| j tƒr,t| j ƒdkr,| j }qZt| j tƒrD| j df}qZtd | j ¡ƒ‚nd }| jstj	tj
| j| j||d|dI d H \| _| _n<| j||dI d H }|r²|  |¡}tj
|dI d H \| _| _|  | ¡| _|  ¡  | j ¡ I d H  d S )Nr-   r   z Unknown local address format: {})Úhostr   Ússlr   rO   )rL   r   r)   )r   r2   rQ   Úlenr3   r6   r7   r   r   ra   Zopen_connectionr
   r   r   r   rg   r+   Úpacket_codecr   Ú
_init_connÚdrain)r   rL   ri   r   r*   r   r   r    Ú_connectÏ   s6    
üú	þ
zConnection._connectc                 Ã   sF   | j ||dI dH  d| _t ¡ }| |  ¡ ¡| _| |  ¡ ¡| _dS )z;
        Establishes a connection with the server.
        )rL   ri   NT)	rn   r   r   rb   Zcreate_taskÚ
_send_loopr   Ú
_recv_loopr   )r   rL   ri   Zloopr   r   r    rZ   ö   s
    zConnection.connectc              
   Ã   sÀ   | j s
dS d| _ tj| j| j| jdI dH  | jr¼| j ¡  tj	dkr¼zt
j| j ¡ ddI dH  W nV t
jk
r†   | j d¡ Y n6 tk
rº } z| j dt|ƒ|¡ W 5 d}~X Y nX dS )	zi
        Disconnects from the server, and clears
        pending outgoing and incoming messages.
        NF)Z	send_taskZ	recv_task)r   é   é
   rO   z;Graceful disconnection timed out, forcibly ignoring cleanupz%s during disconnect: %s)r   r   Z_cancelr   r   r   r   ÚcloseÚsysÚversion_infor   ra   Zwait_closedÚTimeoutErrorÚwarningÚ	ExceptionÚinforU   ©r   Úer   r   r    Ú
disconnect  s"    ý

zConnection.disconnectc                 C   s   | j stdƒ‚| j |¡S )zp
        Sends a packet of data through this connection mode.

        This method returns a coroutine.
        úNot connected)r   rV   r   Úput©r   Údatar   r   r    Úsend"  s    zConnection.sendc                 Ã   s8   | j r,| j ¡ I dH \}}|r"|‚|r |S q tdƒ‚dS )zs
        Receives a packet of data through this connection mode.

        This method returns a coroutine.
        Nr}   )r   r   ÚgetrV   )r   ÚresultÚerrr   r   r    Úrecv-  s    zConnection.recvc              
   Ã   s    z2| j r0|  | j ¡ I dH ¡ | j ¡ I dH  qW nh tjk
rH   Y nT tk
rš } z6t	|t
ƒrp| j d¡ n| j d¡ |  ¡ I dH  W 5 d}~X Y nX dS )zS
        This loop is constantly popping items off the queue to send them.
        Nz.The server closed the connection while sendingz%Unexpected exception in the send loop)r   Ú_sendr   r‚   r   rm   r   ÚCancelledErrorrx   r2   ÚIOErrorr   ry   Ú	exceptionr|   rz   r   r   r    ro   <  s    
zConnection._send_loopc              
   Ã   s¢  zŠ| jrŠz|  ¡ I dH }W nP tjk
r<   Y qŠY q ttjfk
r” } z6| j d|¡ | j	 
d|f¡I dH  |   ¡ I dH  W 5 d}~X Y q tk
rØ } z(| j d|¡ | j	 
d|f¡I dH  W 5 d}~X Y q tk
r } z(| j d|¡ | j	 
d|f¡I dH  W 5 d}~X Y q tk
rp } z4| j d¡ | j	 
d|f¡I dH  |   ¡ I dH  W 5 d}~X Y qX | j	 
|df¡I dH  qW 5 |   ¡ I dH  X dS )zU
        This loop is constantly putting items on the queue as they're read.
        Nz Server closed the connection: %sz(Server response had invalid checksum: %sz&Server response had invalid buffer: %sz(Unexpected exception in the receive loop)r|   r   Ú_recvr   r‡   rˆ   ZIncompleteReadErrorr   rw   r   r~   r   r   rx   r‰   )r   r€   r{   r   r   r    rp   N  s,    
&& zConnection._recv_loopc                 C   s   | j jr| j | j j¡ dS )a  
        This method will be called after `connect` is called.
        After this method finishes, the writer will be drained.

        Subclasses should make use of this if they need to send
        data to Telegram to indicate which connection mode will
        be used.
        N)r   Útagr   Úwrite©r   r   r   r    rl   l  s    	zConnection._init_connc                 C   s   | j  | j |¡¡ d S r?   )r   rŒ   r   Úencode_packetr   r   r   r    r†   x  s    zConnection._sendc                 Ã   s   | j  | j¡I d H S r?   )r   Úread_packetr   r   r   r   r    rŠ   {  s    zConnection._recvc                 C   s   d  | j| j| jj dd¡¡S )Nz{}:{}/{}r   Ú )r7   r
   r   rD   r   Úreplacer   r   r   r    Ú__str__~  s
     þzConnection.__str__)TNN)NN)NN)NN)r   rE   rF   Ú__doc__rk   r!   Ústaticmethodr+   r>   rg   rn   rZ   r|   r   r…   ro   rp   rl   r†   rŠ   r’   r   r   r   r    r      s&   
&
e
'
!r   c                   @   s,   e Zd ZdZdZdd„ Zdd„ Zdd„ ZdS )	ÚObfuscatedConnectionzR
    Base class for "obfuscated" connections ("obfuscated2", "mtproto proxy")
    Nc                 C   s    |   | ¡| _| j | jj¡ d S r?   )Úobfuscated_ior   r   rŒ   Úheaderr   r   r   r    rl   Ž  s    zObfuscatedConnection._init_connc                 C   s   | j  | j |¡¡ d S r?   )r   rŒ   r   rŽ   r   r   r   r    r†   ’  s    zObfuscatedConnection._sendc                 Ã   s   | j  | j¡I d H S r?   )r   r   r   r   r   r   r    rŠ   •  s    zObfuscatedConnection._recv)r   rE   rF   r“   r–   rl   r†   rŠ   r   r   r   r    r•   …  s
   r•   c                   @   s8   e Zd ZdZdZdd„ Zejdd„ ƒZejdd„ ƒZ	dS )	ÚPacketCodecz&
    Base class for packet codecs
    Nc                 C   s
   || _ dS )z@
        Codec is created when connection is just made.
        N)Z_conn)r   Ú
connectionr   r   r    r!   ¥  s    zPacketCodec.__init__c                 C   s   t ‚dS )zB
        Encodes single packet and returns encoded bytes.
        N©ÚNotImplementedErrorr   r   r   r    rŽ   «  s    zPacketCodec.encode_packetc                 Ã   s   t ‚dS )zl
        Reads single packet from `reader` object that should have
        `readexactly(n)` method.
        Nrš   )r   Úreaderr   r   r    r   ²  s    zPacketCodec.read_packet)
r   rE   rF   r“   r‹   r!   ÚabcÚabstractmethodrŽ   r   r   r   r   r    r˜   ™  s   	
r˜   )r   r   r[   rt   ri   r%   ÚImportErrorr5   Úerrorsr   r   r   r   ÚABCr   r•   r˜   r   r   r   r    Ú<module>   s$   

  s