U
    ¯ªhâ–  ã                   @   sf  d dl Z d dlZd dlZd dlZd dlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZmZ ddlmZmZmZmZmZmZ ddlmZ ddlmZmZmZ ddl m!Z! ddl"m#Z#m$Z$m%Z% ddl&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8 ddl9m:Z; ddl<m=Z= ddlm>Z> G dd„ dƒZ?dS )é    Né   )Úauthenticatoré   )ÚMessagePacker)ÚMTProtoPlainSender)ÚRequestState)ÚMTProtoState)Ú	TLRequest)ÚhelpersÚutils)ÚBadMessageErrorÚInvalidBufferErrorÚAuthKeyNotFoundÚSecurityErrorÚTypeNotFoundErrorÚrpc_message_to_error)ÚBinaryReader)Ú	RpcResultÚMessageContainerÚ
GzipPacked)ÚLogOutRequest)ÚPingRequestÚDestroySessionRequestÚDestroyAuthKeyRequest)ÚMsgsAckÚPongÚBadServerSaltÚBadMsgNotificationÚFutureSaltsÚMsgNewDetailedInfoÚNewSessionCreatedÚMsgDetailedInfoÚMsgsStateReqÚMsgsStateInfoÚMsgsAllInfoÚMsgResendReqÚuploadÚDestroySessionOkÚDestroySessionNoneÚDestroyAuthKeyOkÚDestroyAuthKeyNoneÚDestroyAuthKeyFail)Útypes)ÚAuthKey)Úretry_rangec                   @   sŽ  e Zd ZdZddddddddœdd„Zd	d
„ Zdd„ Zdd„ Zdd„ ZdOdd„Z	e
dd„ ƒZdd„ Zdd„ Zdd„ ZdPd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d0d1„ Zd2d3„ Zeejjejjej jej!jej"jej#jfƒeej$j%jej$j&jej$j'jfƒd4œd5d6„Z(d7d8„ Z)d9d:„ Z*d;d<„ Z+d=d>„ Z,d?d@„ Z-dAdB„ Z.dCdD„ Z/dEdF„ Z0dGdH„ Z1dIdJ„ Z2dKdL„ Z3dMdN„ Z4dS )QÚMTProtoSenderaô  
    MTProto Mobile Protocol sender
    (https://core.telegram.org/mtproto/description).

    This class is responsible for wrapping requests into `TLMessage`'s,
    sending them over the network and receiving them in a safe manner.

    Automatic reconnection due to temporary network issues is a concern
    for this class as well, including retry of messages that could not
    be sent successfully.

    A new authorization key will be generated on connection if no other
    key exists yet.
    é   r   TN)ÚretriesÚdelayÚauto_reconnectÚconnect_timeoutÚauth_key_callbackÚupdates_queueÚauto_reconnect_callbackc          
   &   C   sr  d | _ || _|t | _|| _|| _|| _|| _|| _|| _	|	| _
t ¡ | _d | _d| _d| _t ¡  ¡ | _| j d ¡ d | _d | _|pŒtd ƒ| _t| j| jd| _t| j| jd| _i | _tƒ | _ t!j"dd| _#t$j%| j&t'j%| j(t)j%| j*t+j%| j,t-j%| j.t/j%| j0t1j%| j2t3j%| j4t5j%| j6t7j%| j8t9j%| j:t;j%| j<t=j%| j<t>j%| j?t@j%| jAtBj%| jAtCj%| jDtEj%| jDtFj%| jDi| _Gd S )NF©Úloggersé
   )Úmaxlen)HÚ_connectionÚ_loggersÚ__name__Ú_logÚ_retriesÚ_delayÚ_auto_reconnectÚ_connect_timeoutÚ_auth_key_callbackÚ_updates_queueÚ_auto_reconnect_callbackÚasyncioÚLockÚ_connect_lockÚ_pingÚ_user_connectedÚ_reconnectingr
   Úget_running_loopÚcreate_futureÚ_disconnectedÚ
set_resultÚ_send_loop_handleÚ_recv_loop_handler-   Úauth_keyr   Ú_stater   Ú_send_queueÚ_pending_stateÚsetÚ_pending_ackÚcollectionsÚdequeÚ
_last_acksr   ÚCONSTRUCTOR_IDÚ_handle_rpc_resultr   Ú_handle_containerr   Ú_handle_gzip_packedr   Ú_handle_pongr   Ú_handle_bad_server_saltr   Ú_handle_bad_notificationr!   Ú_handle_detailed_infor   Ú_handle_new_detailed_infor    Ú_handle_new_session_createdr   Ú_handle_ackr   Ú_handle_future_saltsr"   Ú_handle_state_forgottenr%   r$   Ú_handle_msg_allr'   Ú_handle_destroy_sessionr(   r)   Ú_handle_destroy_auth_keyr*   r+   Ú	_handlers)
ÚselfrS   r9   r1   r2   r3   r4   r5   r6   r7   © rn   úB/tmp/pip-unpacked-wheel-c81u5j2r/telethon/network/mtprotosender.pyÚ__init__0   s~    

                   ízMTProtoSender.__init__c              
   Ã   st   | j 4 I dH šV | jr6| j d¡ W 5 Q I dH R £ dS || _|  ¡ I dH  d| _W 5 Q I dH R £ dS Q I dH R X dS )zV
        Connects to the specified given connection using the given auth key.
        NzUser is already connected!FT)rI   rK   r?   Úinfor<   Ú_connect)rm   Ú
connectionrn   rn   ro   Úconnect|   s    zMTProtoSender.connectc                 C   s   | j S ©N)rK   ©rm   rn   rn   ro   Úis_connectedŠ   s    zMTProtoSender.is_connectedc                 C   s   | j  o| jd k	o| jjS ru   )rL   r<   Ú
_connectedrv   rn   rn   ro   Ú_transport_connected   s
    ÿýz"MTProtoSender._transport_connectedc                 Ã   s   |   ¡ I dH  dS )z‘
        Cleanly disconnects the instance from the network, cancels
        all pending requests, and closes the send and receive loops.
        N)Ú_disconnectrv   rn   rn   ro   Ú
disconnect”   s    zMTProtoSender.disconnectFc                 C   sú   | j stdƒ‚t |¡snzt|ƒ}W n6 tjk
rZ } z| j d||¡ ‚ W 5 d}~X Y nX | j 	|¡ |j
S g }g }d}|D ]f}zt||oŽ|d}W n6 tjk
rÌ } z| j d||¡ ‚ W 5 d}~X Y nX | 	|¡ | 	|j
¡ q~| j |¡ |S dS )a­  
        This method enqueues the given request to be sent. Its send
        state will be saved until a response arrives, and a ``Future``
        that will be resolved when the response arrives will be returned:

        .. code-block:: python

            async def method():
                # Sending (enqueued for the send loop)
                future = sender.send(request)
                # Receiving (waits for the receive loop to read the result)
                result = await future

        Designed like this because Telegram may send the response at
        any point, and it can send other items while one waits for it.
        Once the response for this future arrives, it is set with the
        received result, quite similar to how a ``receive()`` call
        would otherwise work.

        Since the receiving part is "built in" the future, it's
        impossible to await receive a result that was never sent.
        z'Cannot send requests while disconnectedz#Request caused struct.error: %s: %sN)Úafter)rK   ÚConnectionErrorr   Zis_list_liker   ÚstructÚerrorr?   rU   ÚappendÚfutureÚextend)rm   ÚrequestZorderedÚstateÚeÚstatesZfuturesÚreqrn   rn   ro   Úsend›   s.    

zMTProtoSender.sendc                 C   s   t  | j¡S )a  
        Future that resolves when the connection to Telegram
        ends, either by user action or in the background.

        Note that it may resolve in either a ``ConnectionError``
        or any other unexpected error that could not be handled.
        )rG   ZshieldrO   rv   rn   rn   ro   ÚdisconnectedÑ   s    	zMTProtoSender.disconnectedc                 Ã   sv  | j  d| j¡ d}t| jƒD ]²}|s<|  |¡I dH }|s<q| jsÊz|  |¡I dH sXW qW nn tt	j
fk
rÈ } zJ| j  d|t|ƒj|¡ | j ¡ I dH  d}t	 | j¡I dH  W Y ¢qW 5 d}~X Y nX  qq|sætd | j¡ƒ‚td | j¡ƒ}| j|dI dH  |‚t ¡ }| j  d¡ | |  ¡ ¡| _| j  d	¡ | |  ¡ ¡| _| j ¡ rb| ¡ | _| j  d
| j¡ dS )z£
        Performs the actual connection, retrying, generating the
        authorization key if necessary, and starting the send and
        receive loops.
        zConnecting to %s...FNz/Connection error %d during auth_key gen: %s: %sz(Connection to Telegram failed {} time(s)z%auth_key generation failed {} time(s)©r   zStarting send loopzStarting receive loopzConnection to %s complete!)r?   rq   r<   r.   r@   Ú_try_connectrS   Ú_try_gen_auth_keyÚIOErrorrG   ÚTimeoutErrorÚwarningÚtyper>   r{   ÚsleeprA   r}   Úformatrz   r
   rM   ÚdebugÚcreate_taskÚ
_send_looprQ   Ú
_recv_looprR   rO   ÚdonerN   )rm   Ú	connectedÚattemptr…   Zlooprn   rn   ro   rr   Þ   sF      ÿ
zMTProtoSender._connectc              
   Ã   s”   z6| j  d|¡ | jj| jdI d H  | j  d¡ W dS  ttjfk
rŽ } z4| j  d|t	|ƒj
|¡ t | j¡I d H  W Y ¢dS d }~X Y nX d S )NzConnection attempt %d...)ÚtimeoutzConnection success!Tz'Attempt %d at connecting failed: %s: %sF)r?   r“   r<   rt   rC   r   rG   rŽ   r   r   r>   r‘   rA   )rm   r™   r…   rn   rn   ro   r‹     s      ÿzMTProtoSender._try_connectc              
   Ã   s²   t | j| jd}zN| j d|¡ t |¡I d H \| j_| j	_
| jrN|  | j¡ | j d¡ W dS  ttfk
r¬ } z,| j d||¡ t | j¡I d H  W Y ¢dS d }~X Y nX d S )Nr8   zNew auth_key attempt %d...zauth_key generation success!Tz%Attempt %d at new auth_key failed: %sF)r   r<   r=   r?   r“   r   Zdo_authenticationrS   ÚkeyrT   Ztime_offsetrD   r   ÚAssertionErrorr   rG   r‘   rA   )rm   r™   Úplainr…   rn   rn   ro   rŒ   %  s    ÿzMTProtoSender._try_gen_auth_keyc                 Ã   s  | j d kr| j d¡ d S | j d| j ¡ d| _z | j d¡ | j  ¡ I d H  W 5 | j dt| jƒ¡ | j ¡ D ]*}|r|j 	¡ s|j 
|¡ qp|j ¡  qp| j ¡  tj| j| j| jdI d H  | j d| j ¡ d | _ X | jr| j 	¡ s|r| j 
|¡ n| j d ¡ d S )Nz.Not disconnecting (already have no connection)zDisconnecting from %s...Fz#Cancelling %d pending message(s)...©Zsend_loop_handleZrecv_loop_handlezDisconnection from %s complete!zClosing current connection...)r<   r?   rq   rK   r“   ÚlenrV   Úvaluesr   r—   Úset_exceptionÚcancelÚclearr
   Ú_cancelrQ   rR   r{   rO   rP   )rm   r   r„   rn   rn   ro   rz   :  s2    

ýzMTProtoSender._disconnectc                 Ã   s  | j  d¡ | j ¡ I dH  tj| j | j| jdI dH  d| _| j	 
¡  | jrT| jnd}d}d}t|ddD ]Z}z|  ¡ I dH  W n ttjfk
rØ } z.|}| j  d||jj¡ t | j¡I dH  W 5 d}~X Y ql tk
rD } zNt|tƒr&|jd	kr&| j  d
¡ tƒ }d}W Y ¢ qÎn| j  d|¡ W 5 d}~X Y ql tk
rŠ } z(|}| j  d|¡ t | j¡I dH  W 5 d}~X Y qlX | j | j  !¡ ¡ | j  "¡  | j#rÂt $¡  %|  #¡ ¡  qÎqld}|s| j  &d|¡ |rò| 'd¡nd}| j(|dI dH  dS )z:
        Cleanly disconnects and then reconnects.
        z0Closing current connection to begin reconnect...Nrž   Fr   T)Zforce_retryz&Failed reconnection attempt %d with %sé”  úUServer does not know about the current auth key; the session may need to be recreatedúInvalid buffer %sz/Unexpected exception reconnecting on attempt %dz(Automatic reconnection failed %d time(s)rŠ   ))r?   rq   r<   r{   r
   r¤   rQ   rR   rL   rT   ÚresetrB   r@   r.   rr   r   rG   rŽ   Ú	__class__r>   r‘   rA   ÚBufferErrorÚ
isinstancer   Úcoder   r   Ú	ExceptionÚ	exceptionrU   r‚   rV   r    r£   rF   rM   r”   r   Úwith_tracebackrz   )rm   Z
last_errorr1   r™   Úokr…   r   rn   rn   ro   Ú
_reconnect\  sZ    ý
 ÿ"ÿ$
zMTProtoSender._reconnectc                 C   s*   | j r&| js&d| _t ¡  |  |¡¡ dS )z(Starts a reconnection in the background.TN)rK   rL   r
   rM   r”   r±   )rm   r   rn   rn   ro   Ú_start_reconnect¡  s    
zMTProtoSender._start_reconnectc                 C   s.   | j dkr || _ |  t|ƒ¡ n
|  d¡ dS )zŒ
        Send a keep-alive ping. If a pong for the last ping was not received
        yet, this means we're probably not connected.
        N)rJ   rˆ   r   r²   )rm   Zrnd_idrn   rn   ro   Ú_keepalive_ping°  s    
zMTProtoSender._keepalive_pingc              
   Ã   sN  | j rJ| jsJ| jrJttt| jƒƒƒ}| j |¡ | j |¡ | j 	¡  | j
 d¡ | j ¡ I dH \}}|spq | j
 dt|ƒt|ƒ¡ | j |¡}|D ]J}t|tƒsÀt|jtƒrâ|| j|j< q˜|D ]}t|jtƒrÄ|| j|j< qÄq˜z| j |¡I dH  W n@ tk
r: } z | j
 d¡ |  |¡ W Y ¢dS d}~X Y nX | j
 d¡ q dS )zÊ
        This loop is responsible for popping items off the send
        queue, encrypting them, and sending them over the network.

        Besides `connect`, only this method ever sends data.
        zWaiting for messages to send...Nz0Encrypting %d message(s) in %d bytes for sendingz$Connection closed while sending dataz,Encrypted messages put in a queue to be sent)rK   rL   rX   r   r   ÚlistrU   r€   r[   r£   r?   r“   ÚgetrŸ   rT   Zencrypt_message_datar«   rƒ   r	   rV   Úmsg_idr<   rˆ   r   rq   r²   )rm   ÚackÚbatchÚdatar„   Úsr…   rn   rn   ro   r•   ¾  s:    
 ÿ

zMTProtoSender._send_loopc              
   Ã   sÆ  | j rÂ| jsÂ| j d¡ z| j ¡ I dH }W n tjk
rJ   ‚ Y nì ttj	fk
rŽ } z"| j 
d|¡ |  |¡ W Y ¢dS d}~X Y n¨ tk
rö } zL|jdkrÊ| j d|¡ | j|dI dH  n| j d¡ |  |¡ W Y ¢dS d}~X Y n@ tk
r4 } z | j d¡ |  |¡ W Y ¢dS d}~X Y nX z | j |¡}|dkrRW q W n0 tk
r– } z | j 
d	|j|j¡ W Y ¢q W 5 d}~X Y nò tk
rÎ } z| j d
|¡ W Y ¢q W 5 d}~X Y nº tk
rH } z\t|tƒr|jdkr| j 
d¡ | jtƒ dI dH  n| j d|¡ |  |¡ W Y ¢dS d}~X Y n@ tk
r† } z | j d¡ |  |¡ W Y ¢dS d}~X Y nX z|  |¡I dH  W q  tk
r¾   | j d¡ Y q X q dS )zÕ
        This loop is responsible for reading all incoming responses
        from the network, decrypting and handling or dispatching them.

        Besides `connect`, only this method ever receives data.
        z#Receiving items from the network...Nz*Connection closed while receiving data: %si­  z3Server indicated flood error at transport level: %srŠ   zServer sent invalid bufferz$Unhandled error while receiving dataz&Type %08x not found, remaining data %rz5Security error while unpacking a received message: %sr¥   r¦   r§   z%Unhandled error while decrypting dataz%Unhandled error while processing msgs)rK   rL   r?   r“   r<   ÚrecvrG   ZCancelledErrorr   ZIncompleteReadErrorrq   r²   r   r¬   r   rz   r®   r­   rT   Zdecrypt_message_datar   Zinvalid_constructor_idÚ	remainingr   rª   r«   r   Ú_process_message)rm   Úbodyr…   Úmessagern   rn   ro   r–   ñ  sf    





 ÿÿ

zMTProtoSender._recv_loopc                 Ã   s4   | j  |j¡ | j |jj| j¡}||ƒI dH  dS )z¶
        Adds the given message to the list of messages that must be
        acknowledged and dispatches control to different ``_handle_*``
        method based on its type.
        N)rX   Úaddr¶   rl   rµ   Úobjr\   Ú_handle_update)rm   r¿   Úhandlerrn   rn   ro   r½   2  s
    ÿzMTProtoSender._process_messagec                    s|   ˆ j  |d¡}|r|gS g }ˆ j  ¡ D ]}|j|kr&| |j¡ q&|rX‡ fdd„|D ƒS ˆ jD ]}|j|kr^|g  S q^g S )zš
        Pops the states known to match the given ID from pending messages.

        This method should be used when the response isn't specific.
        Nc                    s   g | ]}ˆ j  |¡‘qS rn   )rV   Úpop)Ú.0Úxrv   rn   ro   Ú
<listcomp>M  s     z-MTProtoSender._pop_states.<locals>.<listcomp>)rV   rÄ   r    Zcontainer_idr€   r¶   r[   )rm   r¶   r„   Zto_popr·   rn   rv   ro   Ú_pop_states=  s    


zMTProtoSender._pop_statesc              
   Ã   sp  |j }| j |jd¡}| j d|j¡ |s¢|jrB| j d|j¡ n\z2t|j	ƒ}t
| ¡ tjƒshtdƒ‚W 5 Q R X W n( ttfk
rœ   | j d|j	¡ Y nX dS |jræt|j|jƒ}| j tt|jgƒƒ¡ |j ¡ sä|j |¡ n†z&t|j	ƒ}|j |¡}W 5 Q R X W n< tk
rH } z|j ¡ s8|j |¡ W 5 d}~X Y n$X |  |¡ |j ¡ sl|j |¡ dS )zÐ
        Handles the result for Remote Procedure Calls:

            rpc_result#f35c6d01 req_msg_id:long result:bytes = RpcResult;

        This is where the future results for sent requests are set.
        Nz"Handling RPC result for message %dz)Received error without parent request: %szNot an upload.Filez,Received response without parent request: %s)rÁ   rV   rÄ   Ú
req_msg_idr?   r“   r   rq   r   r¾   r«   Útgread_objectr&   ZFileÚ
ValueErrorr   r   rƒ   rU   r€   r   r   r¶   r   Ú	cancelledr¡   Zread_resultr­   Ú_store_own_updatesrP   )rm   r¿   Z
rpc_resultr„   Úreaderr   Úresultr…   rn   rn   ro   r]   U  s>    ÿ
ÿ

z MTProtoSender._handle_rpc_resultc                 Ã   s.   | j  d¡ |jjD ]}|  |¡I dH  qdS )z¢
        Processes the inner messages of a container with many of them:

            msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
        zHandling containerN)r?   r“   rÁ   Úmessagesr½   )rm   r¿   Zinner_messagern   rn   ro   r^   ‹  s    zMTProtoSender._handle_containerc              	   Ã   sB   | j  d¡ t|jjƒ }| ¡ |_|  |¡I dH  W 5 Q R X dS )zˆ
        Unpacks the data from a gzipped object and processes it:

            gzip_packed#3072cfa1 packed_data:bytes = Object;
        zHandling gzipped dataN)r?   r“   r   rÁ   r¹   rÊ   r½   )rm   r¿   rÎ   rn   rn   ro   r_   •  s    
z!MTProtoSender._handle_gzip_packedc                 Ã   sj   z|j jdkst‚W n. tk
rB   | j d|j jj|j ¡ Y d S X | j d|j jj¡ | j 	|j ¡ d S )Nl   ¬*ê z0Note: %s is not an update, not dispatching it %szHandling update %s)
rÁ   ZSUBCLASS_OF_IDrœ   r?   r   r©   r>   r“   rE   Ú
put_nowait©rm   r¿   rn   rn   ro   rÂ      s    ýzMTProtoSender._handle_update)Ú_update_idsÚ_update_like_idsc                C   sº   z |j |kr d|_| j |¡ n~|j |krxt t g |j|j¡t	j	t
 d¡d d… Ž jt	jjd¡}d|_| j |¡ n&|j tjjj kržd|j_| j |j¡ W n tk
r´   Y nX d S )NTr   é   )Útzinfo)r\   Z_self_outgoingrE   rÑ   Ú_tlÚUpdateShortZUpdateDeleteMessagesZptsZ	pts_countÚdatetimeÚtimeÚgmtimeÚreplaceÚtimezoneÚutcrÐ   ZInvitedUsersZupdatesÚAttributeError)rm   rÁ   rÓ   rÔ   Zupdrn   rn   ro   rÍ   ®  s     


"þz MTProtoSender._store_own_updatesc                 Ã   sL   |j }| j d|j¡ | j|jkr(d| _| j |jd¡}|rH|j 	|¡ dS )zº
        Handles pong results, which don't come inside a ``rpc_result``
        but are still sent through a request:

            pong#347773c5 msg_id:long ping_id:long = Pong;
        zHandling pong for message %dN)
rÁ   r?   r“   r¶   rJ   Zping_idrV   rÄ   r   rP   )rm   r¿   Zpongr„   rn   rn   ro   r`   Õ  s    zMTProtoSender._handle_pongc                 Ã   sN   |j }| j d|j¡ |j| j_|  |j¡}| j 	|¡ | j dt
|ƒ¡ dS )a  
        Corrects the currently used server salt to use the right value
        before enqueuing the rejected message to be re-sent:

            bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int
            error_code:int new_server_salt:long = BadMsgNotification;
        z Handling bad salt for message %dz%d message(s) will be resentN)rÁ   r?   r“   Ú
bad_msg_idZnew_server_saltrT   ÚsaltrÈ   rU   r‚   rŸ   )rm   r¿   Zbad_saltr†   rn   rn   ro   ra   å  s    
z%MTProtoSender._handle_bad_server_saltc                 Ã   sÈ   |j }|  |j¡}| j d|¡ |jdkrJ| jj|jd}| j 	d|¡ n\|jdkrf| j j
d7  _
n@|jdkr‚| j j
d8  _
n$|D ]}|j t|j|jƒ¡ q†d	S | j |¡ | j d
t|ƒ¡ d	S )a  
        Adjusts the current state to be correct based on the
        received bad message notification whenever possible:

            bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int
            error_code:int = BadMsgNotification;
        zHandling bad msg %s)é   é   )Zcorrect_msg_idz-System clock is wrong, set time offset to %dsé    é@   é!   râ   Nz)%d messages will be resent due to bad msg)rÁ   rÈ   rà   r?   r“   Z
error_coderT   Zupdate_time_offsetr¶   rq   Z	_sequencer   r¡   r   rƒ   rU   r‚   rŸ   )rm   r¿   Zbad_msgr†   Útor„   rn   rn   ro   rb   õ  s*    
ÿ

ÿÿz&MTProtoSender._handle_bad_notificationc                 Ã   s&   |j j}| j d|¡ | j |¡ dS )zÏ
        Updates the current status with the received detailed information:

            msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long
            bytes:int status:int = MsgDetailedInfo;
        z%Handling detailed info for message %dN©rÁ   Zanswer_msg_idr?   r“   rX   rÀ   ©rm   r¿   r¶   rn   rn   ro   rc     s    z#MTProtoSender._handle_detailed_infoc                 Ã   s&   |j j}| j d|¡ | j |¡ dS )zÇ
        Updates the current status with the received detailed information:

            msg_new_detailed_info#809db6df answer_msg_id:long
            bytes:int status:int = MsgDetailedInfo;
        z)Handling new detailed info for message %dNrè   ré   rn   rn   ro   rd   %  s    z'MTProtoSender._handle_new_detailed_infoc                 Ã   s   | j  d¡ |jj| j_dS )zÉ
        Updates the current status with the received session information:

            new_session_created#9ec20908 first_msg_id:long unique_id:long
            server_salt:long = NewSession;
        zHandling new session createdN)r?   r“   rÁ   Zserver_saltrT   rá   rÒ   rn   rn   ro   re   1  s    z)MTProtoSender._handle_new_session_createdc                 Ã   sd   |j }| j dt|jƒ¡ |jD ]>}| j |¡}|r t|jt	ƒr | j|= |j
 ¡ s |j
 d¡ q dS )a3  
        Handles a server acknowledge about our messages. Normally
        these can be ignored except in the case of ``auth.logOut``:

            auth.logOut#5717da40 = Bool;

        Telegram doesn't seem to send its result so we need to confirm
        it manually. No other request is known to have this behaviour.

        Since the ID of sent messages consisting of a container is
        never returned (unless on a bad notification), this method
        also removes containers messages when any of their inner
        messages are acknowledged.
        zHandling acknowledge for %sTN)rÁ   r?   r“   ÚstrÚmsg_idsrV   rµ   r«   rƒ   r   r   rÌ   rP   )rm   r¿   r·   r¶   r„   rn   rn   ro   rf   <  s    

zMTProtoSender._handle_ackc                 Ã   s6   | j  d|j¡ | j |jd¡}|r2|j |j¡ dS )zõ
        Handles future salt results, which don't come inside a
        ``rpc_result`` but are still sent through a request:

            future_salts#ae500895 req_msg_id:long now:int
            salts:vector<future_salt> = FutureSalts;
        z$Handling future salts for message %dN)r?   r“   r¶   rV   rÄ   r   rP   rÁ   )rm   r¿   r„   rn   rn   ro   rg   T  s    
z"MTProtoSender._handle_future_saltsc                 Ã   s.   | j  tt|jtdƒt|jjƒ dƒ¡ dS )z
        Handles both :tl:`MsgsStateReq` and :tl:`MsgResendReq` by
        enqueuing a :tl:`MsgsStateInfo` to be sent at a later point.
        r   )rÉ   rq   N)	rU   r€   r   r#   r¶   ÚchrrŸ   rÁ   rë   rÒ   rn   rn   ro   rh   c  s    
 ÿz%MTProtoSender._handle_state_forgottenc                 Ã   s   dS )zC
        Handles :tl:`MsgsAllInfo` by doing nothing (yet).
        Nrn   rÒ   rn   rn   ro   ri   l  s    zMTProtoSender._handle_msg_allc                 Ã   s\   | j  ¡ D ](\}}t|jtƒr
|jj|jjkr
 q8q
dS | j |= |j ¡ sX|j 	|j¡ dS )z
        Handles both :tl:`DestroySessionOk` and :tl:`DestroySessionNone`.
        It behaves pretty much like handling an RPC result.
        N)
rV   Úitemsr«   rƒ   r   Z
session_idrÁ   r   rÌ   rP   ©rm   r¿   r¶   r„   rn   rn   ro   rj   q  s    ÿ
z%MTProtoSender._handle_destroy_sessionc                 Ã   sx   | j  d|j¡ t| j ¡ ƒD ]4\}}t|jtƒr| j|= |j	 
¡ s|j	 |j¡ qt|jtƒrt| jtƒ dI dH  dS )a  
        Handles :tl:`DestroyAuthKeyFail`, :tl:`DestroyAuthKeyNone`, and :tl:`DestroyAuthKeyOk`.

        :tl:`DestroyAuthKey` is not intended for users to use, but they still
        might, and the response won't come in `rpc_result`, so thhat's worked
        around here.
        zHandling destroy auth key %srŠ   N)r?   r“   rÁ   r´   rV   rí   r«   rƒ   r   r   rÌ   rP   r)   rz   r   rî   rn   rn   ro   rk     s    
z&MTProtoSender._handle_destroy_auth_key)F)N)5r>   Ú
__module__Ú__qualname__Ú__doc__rp   rt   rw   ry   r{   rˆ   Úpropertyr‰   rr   r‹   rŒ   rz   r±   r²   r³   r•   r–   r½   rÈ   r]   r^   r_   rÂ   Ú	frozensetr×   ZUpdateShortMessager\   ZUpdateShortChatMessagerØ   ZUpdatesCombinedZUpdatesZUpdateShortSentMessagerÐ   ZAffectedHistoryZAffectedMessagesZAffectedFoundMessagesrÍ   r`   ra   rb   rc   rd   re   rf   rg   rh   ri   rj   rk   rn   rn   rn   ro   r/   !   sr       ýL
6
;
"E3A6
úýù'$	r/   )@rG   rY   r~   rÙ   rÚ   Ú r   Zextensions.messagepackerr   Zmtprotoplainsenderr   Zrequeststater   Zmtprotostater   Ztl.tlobjectr	   r
   r   Úerrorsr   r   r   r   r   r   Ú
extensionsr   Ztl.corer   r   r   Ztl.functions.authr   Ztl.functionsr   r   r   Ztl.typesr   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   Útlr,   r×   Zcryptor-   r.   r/   rn   rn   rn   ro   Ú<module>   s*    P