mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-24 09:16:12 +01:00
Merge pull request #121 from teloxide/throttle_fix
Fix `Throttle` adaptor
This commit is contained in:
commit
156cff7ce5
3 changed files with 63 additions and 4 deletions
|
@ -11,9 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- `EditedMessageIsTooLong` error [#109][pr109]
|
- `EditedMessageIsTooLong` error [#109][pr109]
|
||||||
- `UntilDate` enum and use it for `{Restricted, Banned}::until_date` ([#116][pr116])
|
- `UntilDate` enum and use it for `{Restricted, Banned}::until_date` ([#116][pr116])
|
||||||
|
- `Limits::messages_per_min_channel` ([#121][pr121])
|
||||||
|
|
||||||
[pr109]: https://github.com/teloxide/teloxide-core/pull/109
|
[pr109]: https://github.com/teloxide/teloxide-core/pull/109
|
||||||
[pr116]: https://github.com/teloxide/teloxide-core/pull/116
|
[pr116]: https://github.com/teloxide/teloxide-core/pull/116
|
||||||
|
[pr121]: https://github.com/teloxide/teloxide-core/pull/121
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -26,8 +28,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Type of `BanChatMember::until_date`: `u64` -> `chrono::DateTime<Utc>` ([#116][pr116])
|
- Type of `BanChatMember::until_date`: `u64` -> `chrono::DateTime<Utc>` ([#116][pr116])
|
||||||
- Type of `Poll::correct_option_id`: `i32` -> `u8` ([#119][pr119])
|
- Type of `Poll::correct_option_id`: `i32` -> `u8` ([#119][pr119])
|
||||||
- Type of `Poll::open_period`: `i32` -> `u16` ([#119][pr119])
|
- Type of `Poll::open_period`: `i32` -> `u16` ([#119][pr119])
|
||||||
|
- `Throttle` adaptor not honouring chat/min limits ([#121][pr121])
|
||||||
|
|
||||||
[pr119]: https://github.com/teloxide/teloxide-core/pull/119
|
[pr119]: https://github.com/teloxide/teloxide-core/pull/119
|
||||||
|
|
||||||
## 0.3.3 - 2021-08-03
|
## 0.3.3 - 2021-08-03
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -203,11 +203,15 @@ pub struct Limits {
|
||||||
/// Allowed messages in one chat per minute.
|
/// Allowed messages in one chat per minute.
|
||||||
pub messages_per_min_chat: u32,
|
pub messages_per_min_chat: u32,
|
||||||
|
|
||||||
|
/// Allowed messages in one channel per minute.
|
||||||
|
pub messages_per_min_channel: u32,
|
||||||
|
|
||||||
/// Allowed messages per second.
|
/// Allowed messages per second.
|
||||||
pub messages_per_sec_overall: u32,
|
pub messages_per_sec_overall: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defaults are taken from [telegram documentation][tgdoc].
|
/// Defaults are taken from [telegram documentation][tgdoc] (except for
|
||||||
|
/// `messages_per_min_channel`).
|
||||||
///
|
///
|
||||||
/// [tgdoc]: https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this
|
/// [tgdoc]: https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this
|
||||||
impl Default for Limits {
|
impl Default for Limits {
|
||||||
|
@ -216,6 +220,7 @@ impl Default for Limits {
|
||||||
messages_per_sec_chat: 1,
|
messages_per_sec_chat: 1,
|
||||||
messages_per_sec_overall: 30,
|
messages_per_sec_overall: 30,
|
||||||
messages_per_min_chat: 20,
|
messages_per_min_chat: 20,
|
||||||
|
messages_per_min_channel: 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,9 +470,17 @@ async fn worker(
|
||||||
|
|
||||||
while let Some(entry) = queue_removing.next() {
|
while let Some(entry) = queue_removing.next() {
|
||||||
let chat = &entry.value().0;
|
let chat = &entry.value().0;
|
||||||
let requests_sent_count = requests_sent.per_sec.get(chat).copied().unwrap_or(0);
|
let requests_sent_per_sec_count = requests_sent.per_sec.get(chat).copied().unwrap_or(0);
|
||||||
let limits_not_exceeded = requests_sent_count < limits.messages_per_sec_chat
|
let requests_sent_per_min_count = requests_sent.per_min.get(chat).copied().unwrap_or(0);
|
||||||
&& requests_sent_count < limits.messages_per_min_chat;
|
|
||||||
|
let messages_per_min_limit = if chat.is_channel() {
|
||||||
|
limits.messages_per_min_channel
|
||||||
|
} else {
|
||||||
|
limits.messages_per_min_chat
|
||||||
|
};
|
||||||
|
|
||||||
|
let limits_not_exceeded = requests_sent_per_sec_count < limits.messages_per_sec_chat
|
||||||
|
&& requests_sent_per_min_count < messages_per_min_limit;
|
||||||
|
|
||||||
if limits_not_exceeded {
|
if limits_not_exceeded {
|
||||||
*requests_sent.per_sec.entry(*chat).or_insert(0) += 1;
|
*requests_sent.per_sec.entry(*chat).or_insert(0) += 1;
|
||||||
|
@ -627,6 +640,15 @@ enum ChatIdHash {
|
||||||
ChannelUsernameHash(u64),
|
ChannelUsernameHash(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ChatIdHash {
|
||||||
|
fn is_channel(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Self::Id(id) => ChatId::Id(id).is_channel(),
|
||||||
|
Self::ChannelUsernameHash(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&ChatId> for ChatIdHash {
|
impl From<&ChatId> for ChatIdHash {
|
||||||
fn from(value: &ChatId) -> Self {
|
fn from(value: &ChatId) -> Self {
|
||||||
match value {
|
match value {
|
||||||
|
|
|
@ -15,6 +15,39 @@ pub enum ChatId {
|
||||||
ChannelUsername(String),
|
ChannelUsername(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ChatId {
|
||||||
|
pub(crate) fn is_channel(&self) -> bool {
|
||||||
|
matches!(self.unmark(), None | Some(UnmarkedChatId::Channel(_)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn unmark(&self) -> Option<UnmarkedChatId> {
|
||||||
|
use UnmarkedChatId::*;
|
||||||
|
|
||||||
|
const MAX_CHANNEL_ID: i64 = -(10i64.pow(12));
|
||||||
|
const MIN_CHANNEL_ID: i64 = MAX_CHANNEL_ID - (i32::MAX as i64);
|
||||||
|
const MAX_USER_ID: i64 = i32::MAX as _;
|
||||||
|
const MIN_CHAT_ID: i64 = -MAX_USER_ID;
|
||||||
|
|
||||||
|
let res = match self {
|
||||||
|
&Self::Id(id @ MIN_CHAT_ID..=-1) => Chat(-id as _),
|
||||||
|
&Self::Id(id @ MIN_CHANNEL_ID..=MAX_CHANNEL_ID) => Channel((MAX_CHANNEL_ID - id) as _),
|
||||||
|
&Self::Id(id) => {
|
||||||
|
debug_assert!(0 < id && id < MAX_USER_ID, "malformed chat id");
|
||||||
|
User(id as _)
|
||||||
|
}
|
||||||
|
Self::ChannelUsername(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum UnmarkedChatId {
|
||||||
|
User(u32),
|
||||||
|
Chat(u32),
|
||||||
|
Channel(u32),
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Add table
Reference in a new issue