tgbot/types/definitions/
update.rs

1use std::{collections::HashSet, time::Duration};
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value as JsonValue;
5
6use crate::{
7    api::{Method, Payload},
8    types::{
9        BusinessConnection,
10        BusinessMessagesDeleted,
11        CallbackQuery,
12        Chat,
13        ChatBoostRemoved,
14        ChatBoostUpdated,
15        ChatJoinRequest,
16        ChatMemberUpdated,
17        ChatPeerId,
18        ChatUsername,
19        ChosenInlineResult,
20        InlineQuery,
21        Integer,
22        MaybeInaccessibleMessage,
23        Message,
24        MessageReactionCountUpdated,
25        MessageReactionUpdated,
26        PaidMediaPurchased,
27        Poll,
28        PollAnswer,
29        PollAnswerVoter,
30        PreCheckoutQuery,
31        ShippingQuery,
32        User,
33        UserPeerId,
34        UserUsername,
35    },
36};
37
38/// Represents an incoming update.
39#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
40pub struct Update {
41    /// Unique identifier of the update.
42    ///
43    /// Update identifiers start from a certain positive number and increase sequentially.
44    /// This ID becomes especially handy if you’re using Webhooks, since it allows you to
45    /// ignore repeated updates or to restore the correct update sequence,
46    /// should they get out of order.
47    /// If there are no new updates for at least a week, then identifier
48    /// of the next update will be chosen randomly instead of sequentially.
49    #[serde(rename = "update_id")]
50    pub id: Integer,
51    /// Type of the update.
52    #[serde(flatten)]
53    pub update_type: UpdateType,
54}
55
56impl Update {
57    /// Creates a new `Update`.
58    ///
59    /// # Arguments
60    ///
61    /// * `id` - Unique identifier of the update.
62    /// * `update_type` - Type of the update.
63    pub fn new(id: Integer, update_type: UpdateType) -> Self {
64        Self { id, update_type }
65    }
66
67    /// Returns the chat.
68    pub fn get_chat(&self) -> Option<&Chat> {
69        self.get_message().map(|msg| &msg.chat).or(match self.update_type {
70            UpdateType::BotStatus(ref x) | UpdateType::UserStatus(ref x) => Some(&x.chat),
71            UpdateType::DeletedBusinessMessages(ref x) => Some(&x.chat),
72            UpdateType::ChatBoostRemoved(ref x) => Some(&x.chat),
73            UpdateType::ChatBoostUpdated(ref x) => Some(&x.chat),
74            UpdateType::ChatJoinRequest(ref x) => Some(&x.chat),
75            UpdateType::MessageReaction(ref x) => Some(&x.chat),
76            UpdateType::MessageReactionCount(ref x) => Some(&x.chat),
77            _ => None,
78        })
79    }
80
81    /// Returns the ID of the chat.
82    pub fn get_chat_id(&self) -> Option<ChatPeerId> {
83        self.get_chat().map(|chat| chat.get_id())
84    }
85
86    /// Returns the username of the chat.
87    pub fn get_chat_username(&self) -> Option<&ChatUsername> {
88        self.get_chat().and_then(|chat| chat.get_username())
89    }
90
91    /// Returns the user.
92    pub fn get_user(&self) -> Option<&User> {
93        Some(match self.update_type {
94            UpdateType::BotStatus(ref x) | UpdateType::UserStatus(ref x) => &x.from,
95            UpdateType::BusinessConnection(ref x) => &x.user,
96            UpdateType::CallbackQuery(ref x) => &x.from,
97            UpdateType::ChatBoostRemoved(_) => return None,
98            UpdateType::ChatBoostUpdated(_) => return None,
99            UpdateType::ChatJoinRequest(ref x) => &x.from,
100            UpdateType::ChosenInlineResult(ref x) => &x.from,
101            UpdateType::DeletedBusinessMessages(_) => return None,
102            UpdateType::InlineQuery(ref x) => &x.from,
103            UpdateType::Message(ref x)
104            | UpdateType::BusinessMessage(ref x)
105            | UpdateType::EditedBusinessMessage(ref x)
106            | UpdateType::EditedMessage(ref x)
107            | UpdateType::ChannelPost(ref x)
108            | UpdateType::EditedChannelPost(ref x) => return x.sender.get_user(),
109            UpdateType::MessageReaction(ref x) => return x.user.as_ref(),
110            UpdateType::MessageReactionCount(_) => return None,
111            UpdateType::Poll(_) => return None,
112            UpdateType::PollAnswer(ref x) => match &x.voter {
113                PollAnswerVoter::User(x) => x,
114                PollAnswerVoter::Chat(_) => return None,
115            },
116            UpdateType::PreCheckoutQuery(ref x) => &x.from,
117            UpdateType::PurchasedPaidMedia(ref x) => &x.from,
118            UpdateType::ShippingQuery(ref x) => &x.from,
119            UpdateType::Unknown(_) => return None,
120        })
121    }
122
123    /// Returns the ID of the user.
124    pub fn get_user_id(&self) -> Option<UserPeerId> {
125        self.get_user().map(|user| user.id)
126    }
127
128    /// Returns the username of the user.
129    pub fn get_user_username(&self) -> Option<&UserUsername> {
130        self.get_user().and_then(|user| user.username.as_ref())
131    }
132
133    /// Returns the message.
134    pub fn get_message(&self) -> Option<&Message> {
135        match self.update_type {
136            UpdateType::Message(ref msg)
137            | UpdateType::BusinessMessage(ref msg)
138            | UpdateType::EditedBusinessMessage(ref msg)
139            | UpdateType::EditedMessage(ref msg)
140            | UpdateType::ChannelPost(ref msg)
141            | UpdateType::EditedChannelPost(ref msg) => Some(msg),
142            UpdateType::CallbackQuery(ref query) => match query.message {
143                Some(MaybeInaccessibleMessage::Message(ref msg)) => Some(msg),
144                _ => None,
145            },
146            _ => None,
147        }
148    }
149}
150
151/// Represents a type of an update.
152#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
153#[allow(clippy::large_enum_variant)]
154#[serde(rename_all = "snake_case")]
155pub enum UpdateType {
156    /// The bot chat member status was updated in a chat.
157    ///
158    /// For private chats, this update is received only
159    /// when the bot is blocked or unblocked by the user.
160    #[serde(rename = "my_chat_member")]
161    BotStatus(ChatMemberUpdated),
162    /// The bot was connected to or disconnected from a business account,
163    /// or a user edited an existing connection with the bot.
164    BusinessConnection(BusinessConnection),
165    /// New non-service message from a connected business account.
166    BusinessMessage(Message),
167    /// A new incoming callback query.
168    CallbackQuery(CallbackQuery),
169    /// A new incoming channel post.
170    ChannelPost(Message),
171    /// A boost was removed from a chat.
172    ///
173    /// The bot must be an administrator in the chat to receive these updates.
174    #[serde(rename = "removed_chat_boost")]
175    ChatBoostRemoved(ChatBoostRemoved),
176    /// A chat boost was added or changed.
177    ///
178    /// The bot must be an administrator in the chat to receive these updates.
179    #[serde(rename = "chat_boost")]
180    ChatBoostUpdated(ChatBoostUpdated),
181    /// A request to join the chat has been sent.
182    ///
183    /// The bot must have the `can_invite_users` administrator right
184    /// in the chat to receive these updates.
185    ChatJoinRequest(ChatJoinRequest),
186    /// The result of an inline query that was chosen by a user and sent to their chat partner.
187    ///
188    /// Please see our documentation on the [feedback collecting][1]
189    /// for details on how to enable these updates for your bot.
190    ///
191    /// [1]: https://core.telegram.org/bots/inline#collecting-feedback
192    ChosenInlineResult(ChosenInlineResult),
193    /// Messages were deleted from a connected business account.
194    DeletedBusinessMessages(BusinessMessagesDeleted),
195    /// New version of a message from a connected business account.
196    EditedBusinessMessage(Message),
197    /// A new version of a channel post that is known to the bot and was edited.
198    EditedChannelPost(Message),
199    /// A new version of a message that is known to the bot and was edited.
200    EditedMessage(Message),
201    /// A new incoming [inline][1] query.
202    ///
203    /// [1]: https://core.telegram.org/bots/api#inline-mode
204    InlineQuery(InlineQuery),
205    /// A new incoming message.
206    Message(Message),
207    /// A reaction to a message was changed by a user.
208    ///
209    /// The bot must be an administrator in the chat
210    /// and must explicitly specify [`AllowedUpdate::MessageReaction`]
211    /// in the list of allowed_updates to receive these updates.
212    ///
213    /// The update isn't received for reactions set by bots.
214    MessageReaction(MessageReactionUpdated),
215    /// Reactions to a message with anonymous reactions were changed.
216    ///
217    /// The bot must be an administrator in the chat
218    /// and must explicitly specify [`AllowedUpdate::MessageReactionCount`]
219    /// in the list of allowed_updates to receive these updates.
220    MessageReactionCount(MessageReactionCountUpdated),
221    /// A new poll state.
222    ///
223    /// Bots receive only updates about polls, which are sent or stopped by the bot.
224    Poll(Poll),
225    /// A user changed their answer in a non-anonymous poll
226    ///
227    /// Bots receive new votes only in polls that were sent by the bot itself.
228    PollAnswer(PollAnswer),
229    /// A new incoming pre-checkout query.
230    ///
231    /// Contains full information about checkout
232    PreCheckoutQuery(PreCheckoutQuery),
233    /// A user purchased paid media with a non-empty payload sent by the bot in a non-channel chat.
234    PurchasedPaidMedia(PaidMediaPurchased),
235    /// A new incoming shipping query.
236    ///
237    /// Only for invoices with flexible price.
238    ShippingQuery(ShippingQuery),
239    /// A chat member's status was updated in a chat.
240    ///
241    /// The bot must be an administrator in the chat
242    /// and must explicitly specify [`AllowedUpdate::UserStatus`] in the list
243    /// of `allowed_updates` to receive these updates.
244    #[serde(rename = "chat_member")]
245    UserStatus(ChatMemberUpdated),
246    /// Used for unknown update types.
247    ///
248    /// For example, Telegram introduced a new update type,
249    /// but tgbot does not support it.
250    #[serde(untagged)]
251    Unknown(JsonValue),
252}
253
254/// Conversion of an [`Update`] into `T` failed.
255///
256/// Use [`Update::from`] to get the original update.
257pub struct UnexpectedUpdate(Update);
258
259impl From<UnexpectedUpdate> for Update {
260    fn from(value: UnexpectedUpdate) -> Self {
261        value.0
262    }
263}
264
265impl TryFrom<Update> for BusinessConnection {
266    type Error = UnexpectedUpdate;
267
268    fn try_from(value: Update) -> Result<Self, Self::Error> {
269        use self::UpdateType::*;
270        match value.update_type {
271            BusinessConnection(x) => Ok(x),
272            _ => Err(UnexpectedUpdate(value)),
273        }
274    }
275}
276
277impl TryFrom<Update> for BusinessMessagesDeleted {
278    type Error = UnexpectedUpdate;
279
280    fn try_from(value: Update) -> Result<Self, Self::Error> {
281        use self::UpdateType::*;
282        match value.update_type {
283            DeletedBusinessMessages(x) => Ok(x),
284            _ => Err(UnexpectedUpdate(value)),
285        }
286    }
287}
288
289impl TryFrom<Update> for ChatMemberUpdated {
290    type Error = UnexpectedUpdate;
291
292    fn try_from(value: Update) -> Result<Self, Self::Error> {
293        use self::UpdateType::*;
294        match value.update_type {
295            BotStatus(x) | UserStatus(x) => Ok(x),
296            _ => Err(UnexpectedUpdate(value)),
297        }
298    }
299}
300
301impl TryFrom<Update> for CallbackQuery {
302    type Error = UnexpectedUpdate;
303
304    fn try_from(value: Update) -> Result<Self, Self::Error> {
305        use self::UpdateType::*;
306        match value.update_type {
307            CallbackQuery(x) => Ok(x),
308            _ => Err(UnexpectedUpdate(value)),
309        }
310    }
311}
312
313impl TryFrom<Update> for ChatJoinRequest {
314    type Error = UnexpectedUpdate;
315
316    fn try_from(value: Update) -> Result<Self, Self::Error> {
317        use self::UpdateType::*;
318        match value.update_type {
319            ChatJoinRequest(x) => Ok(x),
320            _ => Err(UnexpectedUpdate(value)),
321        }
322    }
323}
324
325impl TryFrom<Update> for ChosenInlineResult {
326    type Error = UnexpectedUpdate;
327
328    fn try_from(value: Update) -> Result<Self, Self::Error> {
329        use self::UpdateType::*;
330        match value.update_type {
331            ChosenInlineResult(x) => Ok(x),
332            _ => Err(UnexpectedUpdate(value)),
333        }
334    }
335}
336
337impl TryFrom<Update> for InlineQuery {
338    type Error = UnexpectedUpdate;
339
340    fn try_from(value: Update) -> Result<Self, Self::Error> {
341        use self::UpdateType::*;
342        match value.update_type {
343            InlineQuery(x) => Ok(x),
344            _ => Err(UnexpectedUpdate(value)),
345        }
346    }
347}
348
349impl TryFrom<Update> for Message {
350    type Error = UnexpectedUpdate;
351
352    fn try_from(value: Update) -> Result<Self, Self::Error> {
353        use self::UpdateType::*;
354        match value.update_type {
355            BusinessMessage(x)
356            | EditedBusinessMessage(x)
357            | EditedChannelPost(x)
358            | EditedMessage(x)
359            | ChannelPost(x)
360            | Message(x) => Ok(x),
361            _ => Err(UnexpectedUpdate(value)),
362        }
363    }
364}
365
366impl TryFrom<Update> for Poll {
367    type Error = UnexpectedUpdate;
368
369    fn try_from(value: Update) -> Result<Self, Self::Error> {
370        use self::UpdateType::*;
371        match value.update_type {
372            Poll(x) => Ok(x),
373            _ => Err(UnexpectedUpdate(value)),
374        }
375    }
376}
377
378impl TryFrom<Update> for PollAnswer {
379    type Error = UnexpectedUpdate;
380
381    fn try_from(value: Update) -> Result<Self, Self::Error> {
382        use self::UpdateType::*;
383        match value.update_type {
384            PollAnswer(x) => Ok(x),
385            _ => Err(UnexpectedUpdate(value)),
386        }
387    }
388}
389
390impl TryFrom<Update> for PreCheckoutQuery {
391    type Error = UnexpectedUpdate;
392
393    fn try_from(value: Update) -> Result<Self, Self::Error> {
394        use self::UpdateType::*;
395        match value.update_type {
396            PreCheckoutQuery(x) => Ok(x),
397            _ => Err(UnexpectedUpdate(value)),
398        }
399    }
400}
401
402impl TryFrom<Update> for PaidMediaPurchased {
403    type Error = UnexpectedUpdate;
404
405    fn try_from(value: Update) -> Result<Self, Self::Error> {
406        use self::UpdateType::*;
407        match value.update_type {
408            PurchasedPaidMedia(x) => Ok(x),
409            _ => Err(UnexpectedUpdate(value)),
410        }
411    }
412}
413
414impl TryFrom<Update> for ShippingQuery {
415    type Error = UnexpectedUpdate;
416
417    fn try_from(value: Update) -> Result<Self, Self::Error> {
418        use self::UpdateType::*;
419        match value.update_type {
420            ShippingQuery(x) => Ok(x),
421            _ => Err(UnexpectedUpdate(value)),
422        }
423    }
424}
425
426/// Represents a type of update to receive.
427#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
428#[serde(rename_all = "snake_case")]
429pub enum AllowedUpdate {
430    /// The bot chat member status.
431    #[serde(rename = "my_chat_member")]
432    BotStatus,
433    /// Business account connection changes.
434    BusinessConnection,
435    /// New non-service message from a connected business account.
436    BusinessMessage,
437    /// A callback query.
438    CallbackQuery,
439    /// A channel post.
440    ChannelPost,
441    /// A boost was removed from a chat.
442    #[serde(rename = "removed_chat_boost")]
443    ChatBoostRemoved,
444    /// A chat boost was added or changed.
445    #[serde(rename = "chat_boost")]
446    ChatBoostUpdated,
447    /// A request to join a chat.
448    ChatJoinRequest,
449    /// A chosen inline result.
450    ChosenInlineResult,
451    /// Messages were deleted from a connected business account.
452    DeletedBusinessMessages,
453    /// New version of a message from a connected business account.
454    EditedBusinessMessage,
455    /// An edited channel post.
456    EditedChannelPost,
457    /// An edited message.
458    EditedMessage,
459    /// An inline query.
460    InlineQuery,
461    /// A message.
462    Message,
463    /// A reaction to a message.
464    MessageReaction,
465    /// An anonymous reaction to a message.
466    MessageReactionCount,
467    /// A poll.
468    Poll,
469    /// A poll answer.
470    PollAnswer,
471    /// A pre checkout query.
472    PreCheckoutQuery,
473    /// A user purchased paid media.
474    PurchasedPaidMedia,
475    /// A shipping query.
476    ShippingQuery,
477    /// A chat member status.
478    #[serde(rename = "chat_member")]
479    UserStatus,
480}
481
482#[serde_with::skip_serializing_none]
483/// Returns incoming updates using long polling.
484#[derive(Clone, Debug, Default, Serialize)]
485pub struct GetUpdates {
486    allowed_updates: Option<HashSet<AllowedUpdate>>,
487    limit: Option<Integer>,
488    offset: Option<Integer>,
489    timeout: Option<Integer>,
490}
491
492impl Method for GetUpdates {
493    type Response = Vec<Update>;
494
495    fn into_payload(self) -> Payload {
496        Payload::json("getUpdates", self)
497    }
498}
499
500impl GetUpdates {
501    /// Adds a type of an update you want your bot to receive.
502    ///
503    /// # Arguments
504    ///
505    /// * `value` - The type to add.
506    pub fn add_allowed_update(mut self, value: AllowedUpdate) -> Self {
507        match self.allowed_updates {
508            Some(ref mut updates) => {
509                updates.insert(value);
510            }
511            None => {
512                let mut updates = HashSet::new();
513                updates.insert(value);
514                self.allowed_updates = Some(updates);
515            }
516        };
517        self
518    }
519
520    /// Sets a new list of allowed updates.
521    ///
522    /// # Arguments
523    ///
524    /// * `value` - List of the types of updates you want your bot to receive.
525    ///
526    /// For example, specify `[AllowedUpdate::Message, AllowedUpdate::EditedChannelPost]`
527    /// to only receive updates of these types.
528    /// Specify an empty list to receive all updates regardless of type (default).
529    /// If not specified, the previous setting will be used.
530    /// Please note that this parameter doesn't affect updates
531    /// created before the call to the method,
532    /// so unwanted updates may be received for a short period of time.
533    pub fn with_allowed_updates<T>(mut self, value: T) -> Self
534    where
535        T: IntoIterator<Item = AllowedUpdate>,
536    {
537        self.allowed_updates = Some(value.into_iter().collect());
538        self
539    }
540
541    /// Sets a new limit.
542    ///
543    /// # Arguments
544    ///
545    /// * `value` - Limit of the number of updates to be retrieved; 1—100; default - 100.
546    pub fn with_limit(mut self, value: Integer) -> Self {
547        self.limit = Some(value);
548        self
549    }
550
551    /// Sets a new offset.
552    ///
553    /// # Arguments
554    ///
555    /// * `value` - Identifier of the first update to be returned.
556    ///
557    /// Must be greater by one than the highest
558    /// among the identifiers of previously received updates.
559    /// By default, updates starting with the earliest unconfirmed update are returned.
560    /// An update is considered confirmed as soon as the method is called with
561    /// an offset higher than its `update_id`.
562    /// The negative offset can be specified to retrieve updates starting
563    /// from `-offset` update from the end of the updates queue.
564    /// All previous updates will forgotten.
565    pub fn with_offset(mut self, value: Integer) -> Self {
566        self.offset = Some(value);
567        self
568    }
569
570    /// Sets a new timeout.
571    ///
572    /// # Arguments
573    ///
574    /// * `value` - Timeout for long polling; default - 0, i.e. usual short polling; should be positive;
575    ///   short polling should be used for testing purposes only.
576    pub fn with_timeout(mut self, value: Duration) -> Self {
577        self.timeout = Some(value.as_secs() as i64);
578        self
579    }
580}