32
32
except ImportError :
33
33
AIO_LIMITER_AVAILABLE = False
34
34
35
+ from telegram import constants
35
36
from telegram ._utils .logging import get_logger
36
37
from telegram ._utils .types import JSONDict
37
38
from telegram .error import RetryAfter
@@ -86,7 +87,8 @@ class AIORateLimiter(BaseRateLimiter[int]):
86
87
* A :exc:`~telegram.error.RetryAfter` exception will halt *all* requests for
87
88
:attr:`~telegram.error.RetryAfter.retry_after` + 0.1 seconds. This may be stricter than
88
89
necessary in some cases, e.g. the bot may hit a rate limit in one group but might still
89
- be allowed to send messages in another group.
90
+ be allowed to send messages in another group or with
91
+ :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` set to :obj:`True`.
90
92
91
93
Tip:
92
94
With `Bot API 7.1 <https://core.telegram.org/bots/api-changelog#october-31-2024>`_
@@ -96,10 +98,10 @@ class AIORateLimiter(BaseRateLimiter[int]):
96
98
:tg-const:`telegram.constants.FloodLimit.PAID_MESSAGES_PER_SECOND` messages per second by
97
99
paying a fee in Telegram Stars.
98
100
99
- .. caution::
100
- This class currently doesn't take the
101
- :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` parameter into account.
102
- This means that the rate limiting is applied just like for any other message .
101
+ .. versionchanged:: NEXT.VERSION
102
+ This class automatically takes the
103
+ :paramref:`~telegram.Bot.send_message.allow_paid_broadcast` parameter into account and
104
+ throttles the requests accordingly .
103
105
104
106
8000
Note:
105
107
This class is to be understood as minimal effort reference implementation.
@@ -114,23 +116,25 @@ class AIORateLimiter(BaseRateLimiter[int]):
114
116
Args:
115
117
overall_max_rate (:obj:`float`): The maximum number of requests allowed for the entire bot
116
118
per :paramref:`overall_time_period`. When set to 0, no rate limiting will be applied.
117
- Defaults to ``30` `.
119
+ Defaults to :tg-const:`telegram.constants.FloodLimit.MESSAGES_PER_SECOND `.
118
120
overall_time_period (:obj:`float`): The time period (in seconds) during which the
119
121
:paramref:`overall_max_rate` is enforced. When set to 0, no rate limiting will be
120
- applied. Defaults to 1 .
122
+ applied. Defaults to ``1`` .
121
123
group_max_rate (:obj:`float`): The maximum number of requests allowed for requests related
122
124
to groups and channels per :paramref:`group_time_period`. When set to 0, no rate
123
- limiting will be applied. Defaults to 20.
125
+ limiting will be applied. Defaults to
126
+ :tg-const:`telegram.constants.FloodLimit.MESSAGES_PER_MINUTE_PER_GROUP`.
124
127
group_time_period (:obj:`float`): The time period (in seconds) during which the
125
128
:paramref:`group_max_rate` is enforced. When set to 0, no rate limiting will be
126
- applied. Defaults to 60 .
129
+ applied. Defaults to ``60`` .
127
130
max_retries (:obj:`int`): The maximum number of retries to be made in case of a
128
131
:exc:`~telegram.error.RetryAfter` exception.
129
132
If set to 0, no retries will be made. Defaults to ``0``.
130
133
131
134
"""
132
135
133
136
__slots__ = (
137
+ "_apb_limiter" ,
134
138
"_base_limiter" ,
135
139
"_group_limiters" ,
136
140
"_group_max_rate" ,
@@ -141,9 +145,9 @@ class AIORateLimiter(BaseRateLimiter[int]):
141
145
142
146
def __init__ (
143
147
self ,
144
- overall_max_rate : float = 30 ,
148
+ overall_max_rate : float = constants . FloodLimit . MESSAGES_PER_SECOND ,
145
149
overall_time_period : float = 1 ,
146
- group_max_rate : float = 20 ,
150
+ group_max_rate : float = constants . FloodLimit . MESSAGES_PER_MINUTE_PER_GROUP ,
147
151
group_time_period : float = 60 ,
148
152
max_retries : int = 0 ,
149
153
) -> None :
@@ -167,6 +171,9 @@ def __init__(
167
171
self ._group_time_period = 0
168
172
169
173
self ._group_limiters : dict [Union [str , int ], AsyncLimiter ] = {}
174
+ self ._apb_limiter : AsyncLimiter = AsyncLimiter (
175
+ max_rate = constants .FloodLimit .PAID_MESSAGES_PER_SECOND , time_period = 1
176
+ )
170
177
self ._max_retries : int = max_retries
171
178
self ._retry_after_event = asyncio .Event ()
172
179
self ._retry_after_event .set ()
@@ -201,21 +208,30 @@ async def _run_request(
201
208
self ,
202
209
chat : bool ,
203
210
group : Union [str , int , bool ],
211
+ allow_paid_broadcast : bool ,
204
212
callback : Callable [..., Coroutine [Any , Any , Union [bool , JSONDict , list [JSONDict ]]]],
205
213
args : Any ,
206
214
kwargs : dict [str , Any ],
207
215
) -> Union [bool , JSONDict , list [JSONDict ]]:
208
- base_context = self ._base_limiter if (chat and self ._base_limiter ) else null_context ()
209
- group_context = (
210
- self ._get_group_limiter (group ) if group and self ._group_max_rate else null_context ()
211
- )
212
-
213
- async with group_context , base_context :
216
+ async def inner () -> Union [bool , JSONDict , list [JSONDict ]]:
214
217
# In case a retry_after was hit, we wait with processing the request
215
218
await self ._retry_after_event .wait ()
216
-
217
219
return await callback (* args , ** kwargs )
218
220
221
+ if allow_paid_broadcast :
222
+ async with self ._apb_limiter :
223
+ return await inner ()
224
+ else :
225
+ base_context = self ._base_limiter if (chat and self ._base_limiter ) else null_context ()
226
+ group_context = (
227
+ self ._get_group_limiter (group )
228
+ if group and self ._group_max_rate
229
+ else null_context ()
230
+ )
231
+
232
+ async with group_context , base_context :
233
+ return await inner ()
234
+
219
235
# mypy doesn't understand that the last run of the for loop raises an exception
220
236
async def process_request (
221
237
self ,
@@ -242,6 +258,7 @@ async def process_request(
242
258
group : Union [int , str , bool ] = False
243
259
chat : bool = False
244
260
chat_id = data .get ("chat_id" )
261
+ allow_paid_broadcast = data .get ("allow_paid_broadcast" , False )
245
262
if chat_id is not None :
246
263
chat = True
247
264
@@ -257,7 +274,12 @@ async def process_request(
257
274
for i in range (max_retries + 1 ):
258
275
try :
259
276
return await self ._run_request (
260
- chat = chat , group = group , callback = callback , args = args , kwargs = kwargs
277
+ chat = chat ,
278
+ group = group ,
279
+ allow_paid_broadcast = allow_paid_broadcast ,
280
+ callback = callback ,
281
+ args = args ,
282
+ kwargs = kwargs ,
261
283
)
262
284
except RetryAfter as exc :
263
285
if i == max_retries :
0 commit comments