o
    Zzj31  ã                   @   sÂ   d Z ddlZddlZddlmZmZ ddlmZ z
ddlm	Z	 dZ
W n ey-   dZ
Y nw 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 ejZeedd�ZG dd„ dee ƒZdS )zeThis module contains an implementation of the BaseRateLimiter class based on the aiolimiter
library.
é    N)ÚCallableÚ	Coroutine)ÚAny)ÚAsyncLimiterTF)Ú	constants)Ú
get_logger)ÚJSONDict)Ú
RetryAfter)ÚBaseRateLimiterÚAIORateLimiter)Ú
class_namec                   @   s<  e Zd ZdZdZejjdejjddfde	de	de	d	e	d
e
ddfdd„Zd%dd„Zd%dd„Zdee
B eB ddfdd„Zdedee
B eB dededeeeeeB ee B f f dedeeef deeB ee B fdd„ZdedeeeeeB ee B f f dedeeef d ed!eeef d"e
dB deeB ee B fd#d$„ZdS )&r   ak  
    Implementation of :class:`~telegram.ext.BaseRateLimiter` using the library
    `aiolimiter <https://aiolimiter.readthedocs.io/en/stable>`_.

    Important:
        If you want to use this class, you must install PTB with the optional requirement
        ``rate-limiter``, i.e.

        .. code-block:: bash

           pip install "python-telegram-bot[rate-limiter]"

    The rate limiting is applied by combining two levels of throttling and :meth:`process_request`
    roughly boils down to::

        async with group_limiter(group_id):
            async with overall_limiter:
                await callback(*args, **kwargs)

    Here, ``group_id`` is determined by checking if there is a ``chat_id`` parameter in the
    :paramref:`~telegram.ext.BaseRateLimiter.process_request.data`.
    The ``overall_limiter`` is applied only if a ``chat_id`` argument is present at all.

    Attention:
        * Some bot methods accept a ``chat_id`` parameter in form of a ``@username`` for
          supergroups and channels. As we can't know which ``@username`` corresponds to which
          integer ``chat_id``, these will be treated as different groups, which may lead to
          exceeding the rate limit.
        * As channels can't be differentiated from supergroups by the ``@username`` or integer
          ``chat_id``, this also applies the group related rate limits to channels.
        * A :exc:`~telegram.error.RetryAfter` exception will halt *all* requests for
          :attr:`~telegram.error.RetryAfter.retry_after` + 0.1 seconds. This may be stricter than
          necessary in some cases, e.g. the bot may hit a rate limit in one group but might still
          be allowed to send messages in another group or with
          :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` set to :obj:`True`.

    Tip:
        With `Bot API 7.1 <https://core.telegram.org/bots/api-changelog#october-31-2024>`_
        (PTB v27.1), Telegram introduced the parameter
        :paramref:`~telegram.Bot.send_message.allow_paid_broadcast`.
        This allows bots to send up to
        :tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second by
        paying a fee in Telegram Stars.

        .. versionchanged:: 21.11
            This class automatically takes the
            :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` parameter into account and
            throttles the requests accordingly.

    Note:
        This class is to be understood as minimal effort reference implementation.
        If you would like to handle rate limiting in a more sophisticated, fine-tuned way, we
        welcome you to implement your own subclass of :class:`~telegram.ext.BaseRateLimiter`.
        Feel free to check out the source code of this class for inspiration.

    .. seealso:: :wiki:`Avoiding Flood Limits <Avoiding-flood-limits>`

    .. versionadded:: 20.0

    Args:
        overall_max_rate (:obj:`float`): The maximum number of requests allowed for the entire bot
            per :paramref:`overall_time_period`. When set to 0, no rate limiting will be applied.
            Defaults to :tg-const:`telegram.constants.FloodLimit.MESSAGES_PER_SECOND`.
        overall_time_period (:obj:`float`): The time period (in seconds) during which the
            :paramref:`overall_max_rate` is enforced.  When set to 0, no rate limiting will be
            applied. Defaults to ``1``.
        group_max_rate (:obj:`float`): The maximum number of requests allowed for requests related
            to groups and channels per :paramref:`group_time_period`.  When set to 0, no rate
            limiting will be applied. Defaults to
            :tg-const:`telegram.constants.FloodLimit.MESSAGES_PER_MINUTE_PER_GROUP`.
        group_time_period (:obj:`float`): The time period (in seconds) during which the
            :paramref:`group_max_rate` is enforced.  When set to 0, no rate limiting will be
            applied. Defaults to ``60``.
        max_retries (:obj:`int`): The maximum number of retries to be made in case of a
            :exc:`~telegram.error.RetryAfter` exception.
            If set to 0, no retries will be made. Defaults to ``0``.

    )Ú_apb_limiterÚ_base_limiterÚ_group_limitersÚ_group_max_rateÚ_group_time_periodÚ_max_retriesÚ_retry_after_eventé   é<   r   Úoverall_max_rateÚoverall_time_periodÚgroup_max_rateÚgroup_time_periodÚmax_retriesÚreturnNc                 C   s‚   t stdƒ‚|r|rt||d�| _nd | _|r |r || _|| _nd| _d| _i | _ttjj	dd�| _
|| _t ¡ | _| j ¡  d S )NzeTo use `AIORateLimiter`, PTB must be installed via `pip install "python-telegram-bot[rate-limiter]"`.©Úmax_rateÚtime_periodr   r   )ÚAIO_LIMITER_AVAILABLEÚRuntimeErrorr   r   r   r   r   r   Ú
FloodLimitÚPAID_MESSAGES_PER_SECONDr   r   ÚasyncioÚEventr   Úset)Úselfr   r   r   r   r   © r'   úW/var/www/kodo/tsheker/venv/lib/python3.10/site-packages/telegram/ext/_aioratelimiter.pyÚ__init__Œ   s*   ÿ
ÿÿ
zAIORateLimiter.__init__c                 Ã   ó   �dS ©zDoes nothing.Nr'   ©r&   r'   r'   r(   Ú
initialize¯   ó    zAIORateLimiter.initializec                 Ã   r*   r+   r'   r,   r'   r'   r(   Úshutdown²   r.   zAIORateLimiter.shutdownÚgroup_idr   c                 C   sn   t | jƒdkr"| j ¡  ¡ D ]\}}||krq| |j¡r!| j|= q|| jvr2t| j| jd�| j|< | j| S )Ni   r   )	Úlenr   ÚcopyÚitemsÚhas_capacityr   r   r   r   )r&   r0   ÚkeyÚlimiterr'   r'   r(   Ú_get_group_limiterµ   s   €
þ
z!AIORateLimiter._get_group_limiterÚchatÚgroupÚallow_paid_broadcastÚcallback.ÚargsÚkwargsc           
   
   ƒ   s:  �dt tB tt B f‡ ‡‡‡fdd„}|r:ˆj4 I d H š |ƒ I d H W  d   ƒI d H  S 1 I d H s3w   Y  d S |rBˆjrBˆjntƒ }|rOˆjrOˆ |¡ntƒ }	|	4 I d H š8 |4 I d H š |ƒ I d H W  d   ƒI d H  W  d   ƒI d H  S 1 I d H s€w   Y  W d   ƒI d H  d S 1 I d H s–w   Y  d S )Nr   c                   “   s&   �ˆj  ¡ I d H  ˆˆ i ˆ¤ŽI d H S )N)r   Úwaitr'   ©r<   r;   r=   r&   r'   r(   ÚinnerÒ   s   €z*AIORateLimiter._run_request.<locals>.inner)Úboolr   Úlistr   r   Únull_contextr   r7   )
r&   r8   r9   r:   r;   r<   r=   r@   Úbase_contextÚgroup_contextr'   r?   r(   Ú_run_requestÉ   s    €$	
0ÿÿÿý
pÿzAIORateLimiter._run_requestÚendpointÚdataÚrate_limit_argsc                 Ã   s\  �|p| j }d}d}	| d¡}
| dd¡}|
durd}	t tt¡� t|
ƒ}
W d  ƒ n1 s0w   Y  t|
tƒr>|
dk sCt|
tƒrE|
}t	|d ƒD ]`}zXz| j
|	|||||d�I dH W W | j ¡    S  tyž } z-||krztjd	||d
� ‚ |j ¡ d }t d|¡ | j ¡  t |¡I dH  W Y d}~nd}~ww W | j ¡  qK| j ¡  w dS )aÅ  
        Processes a request by applying rate limiting.

        See :meth:`telegram.ext.BaseRateLimiter.process_request` for detailed information on the
        arguments.

        Args:
            rate_limit_args (:obj:`None` | :obj:`int`): If set, specifies the maximum number of
                retries to be made in case of a :exc:`~telegram.error.RetryAfter` exception.
                Defaults to :paramref:`AIORateLimiter.max_retries`.
        FÚchat_idr:   NTr   r   )r8   r9   r:   r;   r<   r=   z*Rate limit hit after maximum of %d retries)Úexc_infogš™™™™™¹?z)Rate limit hit. Retrying after %f seconds)r   ÚgetÚ
contextlibÚsuppressÚ
ValueErrorÚ	TypeErrorÚintÚ
isinstanceÚstrÚrangerF   r   r%   r	   Ú_LOGGERÚ	exceptionÚ_retry_afterÚtotal_secondsÚinfoÚclearr#   Úsleep)r&   r;   r<   r=   rG   rH   rI   r   r9   r8   rJ   r:   ÚiÚexcr[   r'   r'   r(   Úprocess_requestæ   sN   €


ÿúòÿ
€õzAIORateLimiter.process_request)r   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__r   r!   ÚMESSAGES_PER_SECONDÚMESSAGES_PER_MINUTE_PER_GROUPÚfloatrQ   r)   r-   r/   rS   rA   r7   r   r   r   r   rB   ÚdictrF   r^   r'   r'   r'   r(   r   2   sl    Oúþýüûú
ù
#
þ
ýü ûú
ù
ø þý
üû
úùø)rb   r#   rM   Úcollections.abcr   r   Útypingr   Ú
aiolimiterr   r   ÚImportErrorÚtelegramr   Útelegram._utils.loggingr   Útelegram._utils.typesr   Útelegram.errorr	   Útelegram.ext._baseratelimiterr
   ÚnullcontextrC   r_   rU   rQ   r   r'   r'   r'   r(   Ú<module>   s&   ÿ