U
    h;9                     @   s   d Z ddlZddlZddlZddlZ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 G dd dejZeeZd)dd	Zd
d Zdd Zdd ZddddZ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G d#d$ d$e Z!G d%d& d&ej"Z#d'd( Z$dS )+z6Various helpers not related to the Telegram API itself    N)Path)sha1c                   @   s   e Zd ZdZdZdZdS )_EntityTyper         N)__name__
__module____qualname__USERCHATCHANNEL r   r   4/tmp/pip-unpacked-wheel-c81u5j2r/telethon/helpers.pyr      s   r   Tc                 C   s   t jtd| ddS )zEGenerates a random long integer (8 bytes), which is optionally signed   little)signed	byteorder)int
from_bytesosurandomr   r   r   r   generate_random_long   s    r   c                 C   s"   t j| }|rt j|dd dS )z(Ensures that the parent directory existsT)exist_okN)r   pathdirnamemakedirs)	file_pathparentr   r   r   ensure_parent_dir_exists    s    r   c                 C   s   d dd | D S )N c              
   s   sP   | ]H}d t |  krdkrDn n"ddd td|dD n|V  qdS )i   i r    c                 s   s   | ]}t |V  qd S N)chr).0yr   r   r   	<genexpr>+   s     z*add_surrogate.<locals>.<genexpr>.<genexpr>z<HHzutf-16leN)ordjoinstructunpackencoder#   xr   r   r   r%   (   s     ,z add_surrogate.<locals>.<genexpr>)r'   textr   r   r   add_surrogate'   s    
r/   c                 C   s   |  dddS )Nzutf-16surrogatepass)r*   decoder-   r   r   r   del_surrogate0   s    r2   )lengthc                C   sh   |dkrt | }d|  k o&t | k n  ofd| |d    koFdkn  ofd| |   kobdkS   S )zS
    `True` if ``index`` is within a surrogate (before and after it, not at!).
    Nr   u   u   u   )len)r.   indexr3   r   r   r   within_surrogate4   s    r6   c                 C   s   |s|   S t| }|  } |t|  }|  } t| }ttt|D ]}|| }|jdkrf||= qH|j|j |kr|j|kr| j|8  _q|j|j | |_d|_n||= qH|j|j |krqH|j|kr||= qH||j |_qH| S )z
    Strips whitespace from the given surrogated text modifying the provided
    entities, also removing any empty (0-length) entities.

    This assumes that the length of entities is greater or equal to 0, and
    that no entity is out of bounds.
    r   )stripr4   lstriprstripreversedranger3   offset)r.   entitiesZlen_oriZleft_offsetZ	len_finalier   r   r   
strip_textB   s2    

	

r@   c                 c   s<   |r| dks| dk s| d7 } d}|| kr8|d7 }|V  q dS )z
    Generates an integer sequence starting from 1. If `retries` is
    not a zero or a positive integer value, the sequence will be
    infinite, otherwise it will end at `retries + 1`.
    Nr   r   r   )retriesZforce_retryattemptr   r   r   retry_range   s    	rC   c                    s   t | r| I d H S | S d S r!   )inspectisawaitable)valuer   r   r   _maybe_await   s    

rG   c                    s   |  D ]\}}|sq|  z|I dH  W q tjk
rB   Y q tk
rT   Y q tk
r } z"|jdkr| d|t|| W 5 d}~X Y q t	k
r   | d|t|| Y qX qdS )zL
    Helper to cancel one or more tasks gracefully, logging exceptions.
    N)z"yield from wasn't used with futurez4Unhandled exception from %s after cancelling %s (%s))
itemscancelasyncioZCancelledErrorRuntimeErrorAssertionErrorargs	exceptiontype	Exception)logZtasksnameZtaskr?   r   r   r   _cancel   s.    
    rS   c                 C   s8   t | dr| j}n| jj}| r*td||  S )za
    Helps to cut boilerplate on async context
    managers that offer synchronous variants.
    loopz[You must use "async with" if the event loop is running (i.e. you are inside an "async def"))hasattrrT   _clientZ
is_runningrK   run_until_complete
__aenter__)selfrT   r   r   r   _sync_enter   s    
rZ   c                 G   s*   t | dr| j}n| jj}|| j| S )NrT   )rU   rT   rV   rW   	__aexit__)rY   rM   rT   r   r   r   
_sync_exit   s    
r\   c                 C   s   z| j dkrtd| W n" tk
r>   td| Y nX | jj}d|krVtjS d|krdtjS d|krrtj	S d|krtjS td| d S )N)iVl   9 l   F?L i@iwy-l   ]^ iaFl   &4) z {} does not have any entity typez2{} is not a TLObject, cannot determine entity typeZUserZChatZChannelZSelf)
ZSUBCLASS_OF_ID	TypeErrorformatAttributeError	__class__r   r   r
   r   r   )entityrR   r   r   r   _entity_type   s    

rb   c                 C   s   | j dddd} |j dddd}t||   }t| |  }t||  }||dd  }|dd | |dd	  }||fS )
z7Generates the key data corresponding to the given nonce   r   Tr       N         )to_bytesr   digest)Zserver_nonceZ	new_nonceZhash1Zhash2Zhash3keyZivr   r   r   generate_key_data_from_nonce  s    rk   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )	TotalLista  
    A list with an extra `total` property, which may not match its `len`
    since the total represents the total amount of items *available*
    somewhere else, not the items *in this list*.

    Examples:

        .. code-block:: python

            # Telethon returns these lists in some cases (for example,
            # only when a chunk is returned, but the "total" count
            # is available).
            result = await client.get_messages(chat, limit=10)

            print(result.total)  # large number
            print(len(result))  # 10
            print(result[0])  # latest message

            for x in result:  # show the 10 messages
                print(x.text)

    c                    s   t  j|| d| _d S )Nr   )super__init__totalrY   rM   kwargsr`   r   r   rn   8  s    zTotalList.__init__c                 C   s   d ddd | D | jS )N[{}, total={}], c                 s   s   | ]}t |V  qd S r!   )strr+   r   r   r   r%   >  s     z$TotalList.__str__.<locals>.<genexpr>r^   r'   ro   rY   r   r   r   __str__<  s     zTotalList.__str__c                 C   s   d ddd | D | jS )Nrs   rt   c                 s   s   | ]}t |V  qd S r!   )reprr+   r   r   r   r%   B  s     z%TotalList.__repr__.<locals>.<genexpr>rv   rw   r   r   r   __repr__@  s     zTotalList.__repr__)r   r   r	   __doc__rn   rx   rz   __classcell__r   r   rr   r   rl   !  s   rl   c                   @   s   e Zd ZdZddddZdd Zdd	 Zed
d Ze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 d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- ZdS )._FileStreama:  
    Proxy around things that represent a file and need to be used as streams
    which may or not need to be closed.

    This will handle `pathlib.Path`, `str` paths, in-memory `bytes`, and
    anything IO-like (including `aiofiles`).

    It also provides access to the name and file size (also necessary).
    N)	file_sizec                C   s8   t |trt| }|| _d | _|| _d | _d | _d S r!   )	
isinstancer   ru   absolute_file_name_size_stream_close_stream)rY   filer~   r   r   r   rn   O  s    
z_FileStream.__init__c                    s  t | jtrDtj| j| _tj| j| _t	| jd| _
d| _| S t | jtrtt| j| _t| j| _
d| _| S tt| jdd stdt| jdd | _| j| _
d| _| jd krtt| jdd rt| j I d H }nd}|rJt| j I d H }t| jdtjI d H  t| j I d H | _t| j|tjI d H  n:td	 t| j I d H }t|| _t|| _
d| _| S )
NrbTreadz,file description should have a `read` methodrR   Fseekabler   zRCould not determine file size beforehand so the entire file will be read in-memory)r   r   ru   r   r   basenamer   getsizer   openr   r   bytesr4   ioBytesIOcallablegetattrr]   rG   r   tellseekSEEK_ENDSEEK_SET_logwarningr   )rY   r   posdatar   r   r   rX   Y  sB    
z_FileStream.__aenter__c                    s$   | j r | jr t| j I d H  d S r!   )r   r   rG   close)rY   exc_typeexc_valexc_tbr   r   r   r[     s    z_FileStream.__aexit__c                 C   s   | j S r!   )r   rw   r   r   r   r~     s    z_FileStream.file_sizec                 C   s   | j S r!   )r   rw   r   r   r   rR     s    z_FileStream.namec                 O   s   | j j||S r!   )r   r   rp   r   r   r   r         z_FileStream.readc                 O   s   | j j||S r!   )r   readintorp   r   r   r   r     r   z_FileStream.readintoc                 O   s   | j j||S r!   )r   writerp   r   r   r   r     r   z_FileStream.writec                 O   s   | j j||S r!   )r   filenorp   r   r   r   r     r   z_FileStream.filenoc                 O   s   | j j||S r!   )r   flushrp   r   r   r   r     r   z_FileStream.flushc                 O   s   | j j||S r!   )r   isattyrp   r   r   r   r     r   z_FileStream.isattyc                 O   s   | j j||S r!   )r   readablerp   r   r   r   r     r   z_FileStream.readablec                 O   s   | j j||S r!   )r   readlinerp   r   r   r   r     r   z_FileStream.readlinec                 O   s   | j j||S r!   )r   	readlinesrp   r   r   r   r     r   z_FileStream.readlinesc                 O   s   | j j||S r!   )r   r   rp   r   r   r   r     r   z_FileStream.seekc                 O   s   | j j||S r!   )r   r   rp   r   r   r   r     r   z_FileStream.seekablec                 O   s   | j j||S r!   )r   r   rp   r   r   r   r     r   z_FileStream.tellc                 O   s   | j j||S r!   )r   truncaterp   r   r   r   r     r   z_FileStream.truncatec                 O   s   | j j||S r!   )r   writablerp   r   r   r   r     r   z_FileStream.writablec                 O   s   | j j||S r!   )r   
writelinesrp   r   r   r   r     r   z_FileStream.writelinesc                 O   s   d S r!   r   rp   r   r   r   r     s    z_FileStream.close)r   r   r	   r{   rn   rX   r[   propertyr~   rR   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r}   E  s0   	
,

r}   c                   C   sD   t jdkr8z
t W S  tk
r4   t   Y S X nt S d S )N)      )sysversion_inforJ   get_running_looprK   Zget_event_loop_policyZget_event_loopr   r   r   r   r     s    

r   )T)T)%r{   rJ   r   enumr   r(   rD   logging	functoolsr   pathlibr   hashlibr   Enumr   	getLoggerr   r   r   r   r/   r2   r6   r@   rC   rG   rS   rZ   r\   rb   rk   listrl   IOBaser}   r   r   r   r   r   <module>   s:   

	J
%	($f