U
    x0h!?                     @   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-_zbkcapf/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rd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   socks5r	   socks4r   httpzUnknown proxy protocol type: {})SOCKS5SOCKS4HTTP)
isinstancestrlowerpython_socksr,   r1   r2   r3   
ValueErrorformatsocks)
proxy_typeaddrr   rdnsusernamepasswordr,   protocolr1   r2   r3   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 }nd|jkrt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 }ndd l"}
d|d krt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   messagerD   	__class__r   r    r!   {   s    z@Connection._proxy_connect.<locals>.ConnectionErrorExtra.__init__)N)r   
__module____qualname__r!   __classcell__r   r   rF   r    ConnectionErrorExtraz   s   rK   r   )Proxy)	dest_host	dest_porttimeout:F)r*   addressrO   )rM   rN   rO   _socketr	   )&r4   r   tuplelistrA   dict	TypeErrorr9   typer7   ConnectionError_errors
ProxyErrorProxyConnectionErrorZProxyTimeoutErrorZpython_socks.async_.asynciorL   createconnectr
   r   
proxy_hostsocketAF_INET6
proxy_portAF_INETSOCK_STREAMsetblockingbindr   wait_forr   get_running_loopZsock_connectr:   
socksocket	set_proxy
settimeout)r   rO   r   parsedrK   rL   r   r*   moderQ   r:   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   rR   )rO   r   r)   )r   r4   rT   lenr5   r8   r9   r   r   rg   Zopen_connectionr
   r   r   r   rn   r+   packet_codecr   
_init_conndrain)r   rO   rp   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.
        )rO   rp   NT)	ru   r   r   rh   Zcreate_task
_send_loopr   
_recv_loopr   )r   rO   rp   Zloopr   r   r    r^      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rz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      
   rR   z;Graceful disconnection timed out, forcibly ignoring cleanupz%s during disconnect: %s)r   r   Z_cancelr   r   r   r   closesysversion_infor   rg   Zwait_closedTimeoutErrorwarning	ExceptioninforX   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   rY   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   getrY   )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   rt   r   CancelledErrorr   r4   IOErrorr   r   	exceptionr   r   r   r   r    rv   <  s    
zConnection._send_loopc              
      s  z| jrz|  I dH }W nP tjk
r<   Y qY 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   r~   r   r   r   r   r   r   )r   r   r   r   r   r    rw   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    rs   l  s    	zConnection._init_connc                 C   s   | j | j| d S rB   )r   r   r   encode_packetr   r   r   r    r   x  s    zConnection._sendc                    s   | j | jI d H S rB   )r   read_packetr   r   r   r   r    r   {  s    zConnection._recvc                 C   s   d | j| j| jjddS )Nz{}:{}/{}r    )r9   r
   r   rG   r   replacer   r   r   r    __str__~  s
     zConnection.__str__)TNN)NN)NN)NN)r   rH   rI   __doc__rr   r!   staticmethodr+   rA   rn   ru   r^   r   r   r   rv   rw   rs   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 rB   )obfuscated_ior   r   r   headerr   r   r   r    rs     s    zObfuscatedConnection._init_connc                 C   s   | j | j| d S rB   )r   r   r   r   r   r   r   r    r     s    zObfuscatedConnection._sendc                    s   | j | jI d H S rB   )r   r   r   r   r   r   r    r     s    zObfuscatedConnection._recv)r   rH   rI   r   r   rs   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   rH   rI   r   r   r!   abcabstractmethodr   r   r   r   r   r    r     s   	
r   )r   r   r`   r{   rp   r%   ImportErrorr7   errorsr   r   r   r   ABCr   r   r   r   r   r   r    <module>   s$   

  s