a
    /3eO                     @   s  d dl Z d dlZd dlZd dlmZmZmZmZmZm	Z	 d dl
Z
d dlmZ d dlmZ d dlZd dlZd dlmZ d dlmZmZmZmZmZmZmZ zd dlZW n ey   d dlZY n0 dZe dZ!e" Z#g d	Z$g d
Z%g dZ&G dd dej'Z(G dd dZ)G dd dZ*G dd dZ+dd Z,e-e.dddZ/e-e	e-df dddZ0e-e-pdddddZ1e-ej2e-dddZ3e-e4ee- d d!d"Z5efe-e4ee- d d#d$Z6e-e-dd%d&Z7dJej8e.e-d(d)d*Z9dKee-ee-ef f e4ej:d,d-d.Z;d/d0 Z<d1d2 Z=d3d4 Z>d5d6 Z?dLd7d8Z@dMe.ee d:d;d<ZAd=d> ZBd?d@edAdBdCZCe-e-dDdEdFZDe-e-dDdGdHZEdIZFdS )N    N)AnyCallableListDictOptionalUnion)sha256)	parse_qsl)types)is_pil_imageis_dict	is_stringis_byteschunksgenerate_random_tokenpil_image_to_filei   ZTeleBot)textaudiodocumentZ	animationZgameZphotoZstickervideoZ
video_noteZvoicecontactlocationZvenueZdiceZinvoiceZsuccessful_paymentZconnected_websitepollZpassport_dataZweb_app_data)Znew_chat_membersZleft_chat_memberZnew_chat_titleZnew_chat_photoZdelete_chat_photoZgroup_chat_createdZsupergroup_chat_createdZchannel_chat_createdZmigrate_to_chat_idZmigrate_from_chat_idZpinned_messageZproximity_alert_triggeredZvideo_chat_scheduledZvideo_chat_startedZvideo_chat_endedZvideo_chat_participants_invitedZ!message_auto_delete_timer_changedZforum_topic_createdZforum_topic_closedZforum_topic_reopenedZuser_sharedZchat_shared)messageZedited_messageZchannel_postZedited_channel_postZinline_queryZchosen_inline_resultZcallback_queryZshipping_queryZpre_checkout_queryr   Zpoll_answerZmy_chat_memberZchat_memberZchat_join_requestc                   @   sF   e Zd ZdZdZdddZdd Zdd	 Zd
d Zdd Z	dd Z
dS )WorkerThread
    :meta private:
    r   Nc                 C   s   |s&d | jjd }| j jd7  _|s2t }tjj| |d || _d| _t	 | _
t	 | _t	 | _t	 | _|| _d | _d| _|   d S )NzWorkerThread{0}   )nameT)format	__class__countQueue	threadingThread__init__queuedaemonEventreceived_task_event
done_eventexception_eventcontinue_eventexception_callbackexception_info_runningstart)selfr,   r%   r    r1   ?/home/pi/bot/my_env/lib/python3.9/site-packages/telebot/util.pyr$   :   s     



zWorkerThread.__init__c              
   C   s  | j rzx| jjddd\}}}| j  | j  | j  | j  t	d | j
  ||i | t	d | j
  W q  tjy   Y q  ty } zdt	t|jd t|j d t   || _| j
  | jr| | | j | j  W Y d }~q d }~0 0 q d S )NTg      ?)blocktimeoutzReceived taskzTask completez occurred, args=
)r.   r%   getr+   clearr(   r)   r*   loggerdebugsetr!   Empty	Exceptiontype__name__strargs	traceback
format_excr-   r,   wait)r0   taskr@   kwargser1   r1   r2   runO   s*    






*
zWorkerThread.runc                 O   s   | j |||f d S N)r%   put)r0   rD   r@   rE   r1   r1   r2   rI   g   s    zWorkerThread.putc                 C   s   | j  r| jd S rH   r*   is_setr-   r0   r1   r1   r2   raise_exceptionsj   s    
zWorkerThread.raise_exceptionsc                 C   s   | j   | j  d S rH   )r*   r7   r+   r:   rL   r1   r1   r2   clear_exceptionsn   s    
zWorkerThread.clear_exceptionsc                 C   s
   d| _ d S NF)r.   rL   r1   r1   r2   stopr   s    zWorkerThread.stop)NNN)r>   
__module____qualname____doc__r    r$   rG   rI   rM   rN   rP   r1   r1   r1   r2   r   4   s   
r   c                   @   sB   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Zdd Z	dS )
ThreadPoolr      c                    sB   | _ t  _ fddt|D  _| _t  _d  _	d S )Nc                    s   g | ]}t  j jqS r1   )r   on_exceptiontasks).0_rL   r1   r2   
<listcomp>~       z'ThreadPool.__init__.<locals>.<listcomp>)
telebotr!   rW   rangeworkersnum_threadsr"   r'   r*   r-   )r0   r\   r_   r1   rL   r2   r$   {   s    

zThreadPool.__init__c                 O   s   | j |||f d S rH   )rW   rI   )r0   funcr@   rE   r1   r1   r2   rI      s    zThreadPool.putc                 C   sB   | j jd ur| j j|}nd}|s4|| _| j  |j  d S rO   )r\   Zexception_handlerhandler-   r*   r:   r+   )r0   Zworker_threadexc_infoZhandledr1   r1   r2   rV      s    
zThreadPool.on_exceptionc                 C   s   | j  r| jd S rH   rJ   rL   r1   r1   r2   rM      s    
zThreadPool.raise_exceptionsc                 C   s   | j   d S rH   )r*   r7   rL   r1   r1   r2   rN      s    zThreadPool.clear_exceptionsc                 C   s8   | j D ]}|  q| j D ]}|t kr|  qd S rH   )r^   rP   r"   current_threadjoin)r0   Zworkerr1   r1   r2   close   s
    


zThreadPool.closeN)rU   )
r>   rQ   rR   rS   r$   rI   rV   rM   rN   re   r1   r1   r1   r2   rT   v   s   
	
rT   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )		AsyncTaskr   c                 O   s6   || _ || _|| _d| _tj| jd| _| j  d S )NF)target)	rg   r@   rE   doner"   r#   _runthreadr/   )r0   rg   r@   rE   r1   r1   r2   r$      s    zAsyncTask.__init__c              
   C   sP   z| j | ji | j| _W n* tyD } z|| _W Y d }~n
d }~0 0 d| _d S )NT)rg   r@   rE   resultr<   rh   )r0   rF   r1   r1   r2   ri      s
    zAsyncTask._runc                 C   s.   | j s| j  t| jtr$| jn| jS d S rH   )rh   rj   rd   
isinstancerk   BaseExceptionrL   r1   r1   r2   rC      s
    
zAsyncTask.waitN)r>   rQ   rR   rS   r$   ri   rC   r1   r1   r1   r2   rf      s   	rf   c                   @   s"   e Zd ZdZd	ddZdd ZdS )
CustomRequestResponser       c                 C   s   || _ || _|| _d S rH   )status_coder   reason)r0   Z	json_textrq   rr   r1   r1   r2   r$      s    zCustomRequestResponse.__init__c                 C   s   t | jS rH   )jsonloadsr   rL   r1   r1   r2   rs      s    zCustomRequestResponse.jsonN)ro   rp   )r>   rQ   rR   rS   r$   rs   r1   r1   r1   r2   rn      s   
rn   c                  C   s   dd } | S )r   c                    s    fdd}|S )Nc                     s   t  g| R i |S rH   )rf   )r@   rE   fnr1   r2   wrapper   s    z-async_dec.<locals>.decorator.<locals>.wrapperr1   )rv   rw   r1   ru   r2   	decorator   s    zasync_dec.<locals>.decoratorr1   )rx   r1   r1   r2   	async_dec   s    ry   )r   returnc                 C   s   | du rdS |  dS )z
    Checks if `text` is a command. Telegram chat commands start with the '/' character.
    
    :param text: Text to check.
    :type text: :obj:`str`

    :return: True if `text` is a command, else False.
    :rtype: :obj:`bool`
    NF/)
startswithr   r1   r1   r2   
is_command   s    
r~   c                 C   s6   | du rdS t | r2|  d dd dd S dS )av  
    Extracts the command from `text` (minus the '/') if `text` is a command (see is_command).
    If `text` is not a command, this function returns None.

    .. code-block:: python3
        :caption: Examples:
        
        extract_command('/help'): 'help'
        extract_command('/help@BotName'): 'help'
        extract_command('/search black eyed peas'): 'search'
        extract_command('Good day to you'): None

    :param text: String to extract the command from
    :type text: :obj:`str`

    :return: the command if `text` is a command (according to is_command), else None.
    :rtype: :obj:`str` or :obj:`None`
    Nr   @r   )r~   splitr}   r1   r1   r2   extract_command   s    r   c                 C   s.   t dt j}|| }t| r*|dS dS )a  
    Returns the argument after the command.
    
    .. code-block:: python3
        :caption: Examples:

        extract_arguments("/get name"): 'name'
        extract_arguments("/get"): ''
        extract_arguments("/get@botName name"): 'name'
    
    :param text: String to extract the arguments from a command
    :type text: :obj:`str`

    :return: the arguments if `text` is a command (according to is_command), else None.
    :rtype: :obj:`str` or :obj:`None`
    z/\w*(@\w*)*\s*([\s\S]*)rU   N)recompile
IGNORECASEmatchr~   group)r   regexprk   r1   r1   r2   extract_arguments   s    
r   )r   rF   rz   c                 C   s   d}d}|   }t|}d}|D ]Z}|d@ dkrr||jkr@|}n||j |jkrX|} q||dkrj|d7 }n|d7 }|d7 }q |||  S )a  
    Returns the content of the entity.
    
    :param text: The text of the message the entity belongs to
    :type text: :obj:`str`
    
    :param e: The entity to extract
    :type e: :obj:`MessageEntity`
    
    :return: The content of the entity
    :rtype: :obj:`str`
    r            rU   r   )encodelenoffsetlengthdecode)r   rF   r   r/   Zencoded_textendibyter1   r1   r2   extract_entity  s"    


r   )r   chars_per_stringrz   c                    s     fddt dt D S )a  
    Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
    This is very useful for splitting one giant message into multiples.

    :param text: The text to split
    :type text: :obj:`str`

    :param chars_per_string: The number of characters per line the text is split into.
    :type chars_per_string: :obj:`int`

    :return: The splitted text as a list of strings.
    :rtype: :obj:`list` of :obj:`str`
    c                    s   g | ]}||   qS r1   r1   )rX   r   r   r   r1   r2   rZ   D  r[   z split_string.<locals>.<listcomp>r   )r]   r   )r   r   r1   r   r2   split_string6  s    r   c                    s   t t d fdd}|tkr t}g }t| |k r>||  |S | d|  d v r\|d n"d v rn|d nd v r~|d |  | t d } q$dS )aT  
    Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
    This is very useful for splitting one giant message into multiples.
    If `chars_per_string` > 4096: `chars_per_string` = 4096.
    Splits by '\n', '. ' or ' ' in exactly this priority.

    :param text: The text to split
    :type text: :obj:`str`

    :param chars_per_string: The number of maximum characters per part the text is split to.
    :type chars_per_string: :obj:`int`

    :return: The splitted text as a list of strings.
    :rtype: :obj:`list` of :obj:`str`
    )substrrz   c                    s   |   | d d |  S )N)rd   r   )r   partr1   r2   _text_before_lastX  s    z&smart_split.<locals>._text_before_lastNr5   z.  )r?   MAX_MESSAGE_LENGTHr   append)r   r   r   partsr1   r   r2   smart_splitG  s    



r   c                 C   s:   dddd}| du rdS |  D ]\}}| ||} q | S )z
    Replaces the following chars in `text` ('&' with '&amp;', '<' with '&lt;' and '>' with '&gt;').

    :param text: the text to escape
    :return: the escaped text
    z&amp;z&lt;z&gt;)&<>N)itemsreplace)r   charsoldnewr1   r1   r2   escapep  s    r   F)user
include_idrz   c                 C   s4   t | j}d| j d| d|r.d| j dnd S )a  
    Returns an HTML user link. This is useful for reports.
    Attention: Don't forget to set parse_mode to 'HTML'!


    .. code-block:: python3
        :caption: Example:

        bot.send_message(your_user_id, user_link(message.from_user) + ' started the bot!', parse_mode='HTML')

    .. note::
        You can use formatting.* for all other formatting options(bold, italic, links, and etc.)
        This method is kept for backward compatibility, and it is recommended to use formatting.* for
        more options.

    :param user: the user (not the user_id)
    :type user: :obj:`telebot.types.User`

    :param include_id: include the user_id
    :type include_id: :obj:`bool`

    :return: HTML user link
    :rtype: :obj:`str`
    z<a href='tg://user?id=z'>z</a>z (<pre>z</pre>)rp   )r   Z
first_nameid)r   r   r   r1   r1   r2   	user_link  s    
r   rU   )values	row_widthrz   c                 C   s,   t j|d}dd |  D }|j|  |S )aK  
    Returns a reply markup from a dict in this format: {'text': kwargs}
    This is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)' 
    
    Example:

    .. code-block:: python3
        :caption: Using quick_markup:

        from telebot.util import quick_markup

        markup = quick_markup({
            'Twitter': {'url': 'https://twitter.com'},
            'Facebook': {'url': 'https://facebook.com'},
            'Back': {'callback_data': 'whatever'}
        }, row_width=2)
        # returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook
        # and a back button below

        # kwargs can be: 
        {
            'url': None, 
            'callback_data': None, 
            'switch_inline_query': None,
            'switch_inline_query_current_chat': None,
            'callback_game': None,
            'pay': None,
            'login_url': None,
            'web_app': None
        }
    
    :param values: a dict containing all buttons to create in this format: {text: kwargs} {str:}
    :type values: :obj:`dict`

    :param row_width: number of :class:`telebot.types.InlineKeyboardButton` objects on each row
    :type row_width: :obj:`int`

    :return: InlineKeyboardMarkup
    :rtype: :obj:`types.InlineKeyboardMarkup`
    )r   c                 S   s$   g | ]\}}t jf d |i|qS r}   )r
   ZInlineKeyboardButton)rX   r   rE   r1   r1   r2   rZ     s   z quick_markup.<locals>.<listcomp>)r
   InlineKeyboardMarkupr   add)r   r   ZmarkupZbuttonsr1   r1   r2   quick_markup  s    )
r   c                 C   s   |    |   dS r   N)_setchangedrL   r1   r1   r2   or_set  s    r   c                 C   s   |    |   dS r   )_clearr   rL   r1   r1   r2   or_clear  s    r   c                    sJ   t  ds j _t  ds$ j _| _ fdd _ fdd _dS )r   r   r   c                      s   t  S rH   )r   r1   rF   r1   r2   <lambda>  r[   zorify.<locals>.<lambda>c                      s   t  S rH   )r   r1   r   r1   r2   r     r[   N)hasattrr:   r   r7   r   r   )rF   Zchanged_callbackr1   r   r2   orify  s    

r   c                     sN   t   fdd}fdd} D ]}t|| q&j_|_|  S )r   c                     s,   dd  D } t | r   n  d S )Nc                 S   s   g | ]}|  qS r1   )rK   )rX   Zevr1   r1   r2   rZ     r[   z,OrEvent.<locals>.changed.<locals>.<listcomp>)anyr:   r7   )Zboolseventsor_eventr1   r2   r     s    
zOrEvent.<locals>.changedc                      s      s d q d S )N   )rK   _waitr1   )r   r1   r2   	busy_wait  s    zOrEvent.<locals>.busy_wait)r"   r'   r   rC   r   )r   r   r   rF   r1   r   r2   OrEvent  s    r   c                 C   s*   |st t| s | }tt| | tt| S )r   )r   thread_localsetattrgetattr)keyZconstruct_valueresetvaluer1   r1   r2   
per_thread  s    r   T)warnalternativec                    s    fdd}|S )a  
    Use this decorator to mark functions as deprecated.
    When the function is used, an info (or warning if `warn` is True) is logged.

    :meta private:
    
    :param warn: If True a warning is logged else an info
    :type warn: :obj:`bool`

    :param alternative: The new function to use instead
    :type alternative: :obj:`Callable`

    :param deprecation_text: Custom deprecation text
    :type deprecation_text: :obj:`str`

    :return: The decorated function
    c                    s    fdd}|S )Nc                     s\   dj  d} r$|d j  d7 }r4|d 7 }sDt| n
t| | i |S )N`z` is deprecated.z Use `z	` insteadr   )r>   r8   infowarning)r@   rE   r   )r   deprecation_textfunctionr   r1   r2   rw   &  s    
z.deprecated.<locals>.decorator.<locals>.wrapperr1   )r   rw   r   r   r   r   r2   rx   %  s    zdeprecated.<locals>.decoratorr1   )r   r   r   rx   r1   r   r2   
deprecated  s    r   c              
   C   sf   |j r^z&| }tj|}| |g W dS  tyZ } zt| W Y d}~dS d}~0 0 ndS dS )a(  
    A webhook endpoint for Google Cloud Functions FaaS.
    
    :param bot: The bot instance
    :type bot: :obj:`telebot.TeleBot` or :obj:`telebot.async_telebot.AsyncTeleBot`

    :param request: The request object
    :type request: :obj:`flask.Request`

    :return: The response object
    rp   N)zBot FAILi  zBot ON)Zis_jsonZget_jsonr
   ZUpdateZde_jsonZprocess_new_updatesr<   print)ZbotrequestZrequest_jsonupdaterF   r1   r1   r2   webhook_google_functions8  s    r      )number_retriesr   c                O   s   ddl m} ddlm} t|d D ]^}z| |i |W   S  |y } z,|jdkrj||jd d  n W Y d}~q$d}~0 0 q$| |i |S )	a  
    Use this function inside loops in order to avoid getting TooManyRequests error.
    Example:
    
    .. code-block:: python3
    
        from telebot.util import antiflood
        for chat_id in chat_id_list:
        msg = antiflood(bot.send_message, chat_id, text)
        
    :param function: The function to call
    :type function: :obj:`Callable`

    :param number_retries: Number of retries to send
    :type function: :obj:int

    :param args: The arguments to pass to the function
    :type args: :obj:`tuple`

    :param kwargs: The keyword arguments to pass to the function
    :type kwargs: :obj:`dict`

    :return: None
    r   )ApiTelegramException)sleepr   i  
parametersretry_afterN)Ztelebot.apihelperr   timer   r]   Z
error_codeZresult_json)r   r   r@   rE   r   r   rY   exr1   r1   r2   	antifloodQ  s    
r   )tokenraw_init_datac              	   C   s`   t | |}|sdS i }t|D ]<\}}zt|}W n tjyP   |||< Y q0 |||< q|S )z
    Parses web app data.

    :param token: The bot token
    :type token: :obj:`str`

    :param raw_init_data: The raw init data
    :type raw_init_data: :obj:`str`

    :return: The parsed init data
    F)validate_web_app_datar	   rs   rt   JSONDecodeError)r   r   Zis_validrk   r   r   r1   r1   r2   parse_web_app_datay  s    

r   c                 C   s   zt t|}W n ty$   Y dS 0 d|vr2dS |d}ddd t| D }tjd| 	 t
d}t| |	 t
 |kS )z
    Validates web app data.

    :param token: The bot token
    :type token: :obj:`str`

    :param raw_init_data: The raw init data
    :type raw_init_data: :obj:`str`

    :return: The parsed init data
    Fhashr5   c                 s   s    | ]\}}| d | V  qdS )=Nr1   )rX   r   r   r1   r1   r2   	<genexpr>  r[   z(validate_web_app_data.<locals>.<genexpr>s
   WebAppData)r   msg	digestmod)dictr	   
ValueErrorpoprd   sortedr   hmacr   r   r   digest	hexdigest)r   r   Zparsed_dataZinit_data_hashZdata_check_stringZ
secret_keyr1   r1   r2   r     s    
r   ) content_type_mediacontent_type_serviceupdate_typesr   rf   rn   ry   r   r   r   r   r   r   r   r   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )F)rU   )F)TNN)Gr   r"   rA   typingr   r   r   r   r   r   r   hashlibr   urllib.parser	   r%   r!   loggingr\   r
   Ztelebot.service_utilsr   r   r   r   r   r   r   Zujsonrs   ImportErrorr   	getLoggerr8   localr   r   r   r   r#   r   rT   rf   rn   ry   r?   boolr~   r   r   ZMessageEntityr   intr   r   r   ZUserr   r   r   r   r   r   r   r   r   r   r   r   r   __all__r1   r1   r1   r2   <module>   sZ    $
	B*")&3
&(