1use layer_tl_types as tl;
8use layer_tl_types::{Cursor, Deserializable};
9
10use crate::{Client, InvocationError as Error};
11
12#[derive(Clone)]
16pub struct IncomingMessage {
17 pub raw: tl::enums::Message,
19 pub client: Option<Client>,
25}
26
27impl std::fmt::Debug for IncomingMessage {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 f.debug_struct("IncomingMessage")
30 .field("raw", &self.raw)
31 .field("has_client", &self.client.is_some())
32 .finish()
33 }
34}
35
36impl IncomingMessage {
37 pub fn from_raw(raw: tl::enums::Message) -> Self {
38 Self { raw, client: None }
39 }
40
41 pub fn with_client(mut self, client: Client) -> Self {
51 self.client = Some(client);
52 self
53 }
54
55 fn require_client(&self, method: &str) -> Result<&Client, Error> {
57 self.client.as_ref().ok_or_else(|| {
58 Error::Deserialize(format!(
59 "{method}: this IncomingMessage has no embedded client: \
60 use the `_with` variant and pass a &Client explicitly"
61 ))
62 })
63 }
64
65 pub fn text(&self) -> Option<&str> {
67 match &self.raw {
68 tl::enums::Message::Message(m) => {
69 if m.message.is_empty() {
70 None
71 } else {
72 Some(&m.message)
73 }
74 }
75 _ => None,
76 }
77 }
78
79 pub fn id(&self) -> i32 {
81 match &self.raw {
82 tl::enums::Message::Message(m) => m.id,
83 tl::enums::Message::Service(m) => m.id,
84 tl::enums::Message::Empty(m) => m.id,
85 }
86 }
87
88 pub fn peer_id(&self) -> Option<&tl::enums::Peer> {
90 match &self.raw {
91 tl::enums::Message::Message(m) => Some(&m.peer_id),
92 tl::enums::Message::Service(m) => Some(&m.peer_id),
93 _ => None,
94 }
95 }
96
97 pub fn sender_id(&self) -> Option<&tl::enums::Peer> {
99 match &self.raw {
100 tl::enums::Message::Message(m) => m.from_id.as_ref(),
101 tl::enums::Message::Service(m) => m.from_id.as_ref(),
102 _ => None,
103 }
104 }
105
106 pub fn outgoing(&self) -> bool {
108 match &self.raw {
109 tl::enums::Message::Message(m) => m.out,
110 tl::enums::Message::Service(m) => m.out,
111 _ => false,
112 }
113 }
114
115 pub fn date(&self) -> i32 {
117 match &self.raw {
118 tl::enums::Message::Message(m) => m.date,
119 tl::enums::Message::Service(m) => m.date,
120 _ => 0,
121 }
122 }
123
124 pub fn edit_date(&self) -> Option<i32> {
126 match &self.raw {
127 tl::enums::Message::Message(m) => m.edit_date,
128 _ => None,
129 }
130 }
131
132 pub fn mentioned(&self) -> bool {
134 match &self.raw {
135 tl::enums::Message::Message(m) => m.mentioned,
136 tl::enums::Message::Service(m) => m.mentioned,
137 _ => false,
138 }
139 }
140
141 pub fn silent(&self) -> bool {
143 match &self.raw {
144 tl::enums::Message::Message(m) => m.silent,
145 tl::enums::Message::Service(m) => m.silent,
146 _ => false,
147 }
148 }
149
150 pub fn post(&self) -> bool {
152 match &self.raw {
153 tl::enums::Message::Message(m) => m.post,
154 _ => false,
155 }
156 }
157
158 pub fn pinned(&self) -> bool {
160 match &self.raw {
161 tl::enums::Message::Message(m) => m.pinned,
162 _ => false,
163 }
164 }
165
166 pub fn forward_count(&self) -> Option<i32> {
168 match &self.raw {
169 tl::enums::Message::Message(m) => m.forwards,
170 _ => None,
171 }
172 }
173
174 pub fn view_count(&self) -> Option<i32> {
176 match &self.raw {
177 tl::enums::Message::Message(m) => m.views,
178 _ => None,
179 }
180 }
181
182 pub fn reply_count(&self) -> Option<i32> {
184 match &self.raw {
185 tl::enums::Message::Message(m) => m.replies.as_ref().map(|r| match r {
186 tl::enums::MessageReplies::MessageReplies(x) => x.replies,
187 }),
188 _ => None,
189 }
190 }
191
192 pub fn reply_to_message_id(&self) -> Option<i32> {
194 match &self.raw {
195 tl::enums::Message::Message(m) => m.reply_to.as_ref().and_then(|r| match r {
196 tl::enums::MessageReplyHeader::MessageReplyHeader(h) => h.reply_to_msg_id,
197 _ => None,
198 }),
199 _ => None,
200 }
201 }
202
203 pub async fn reply_to_message(
211 &self,
212 client: &Client,
213 ) -> Result<Option<IncomingMessage>, Error> {
214 let reply_id = match self.reply_to_message_id() {
215 Some(id) => id,
216 None => return Ok(None),
217 };
218 let peer = match self.peer_id() {
219 Some(p) => p.clone(),
220 None => return Ok(None),
221 };
222 let msgs = client.get_messages_by_id(peer, &[reply_id]).await?;
223 Ok(msgs.into_iter().next())
224 }
225
226 pub fn date_utc(&self) -> Option<chrono::DateTime<chrono::Utc>> {
230 use chrono::TimeZone;
231 let ts = self.date();
232 if ts == 0 {
233 return None;
234 }
235 chrono::Utc.timestamp_opt(ts as i64, 0).single()
236 }
237
238 pub fn edit_date_utc(&self) -> Option<chrono::DateTime<chrono::Utc>> {
240 use chrono::TimeZone;
241 self.edit_date()
242 .and_then(|ts| chrono::Utc.timestamp_opt(ts as i64, 0).single())
243 }
244
245 pub fn media(&self) -> Option<&tl::enums::MessageMedia> {
247 match &self.raw {
248 tl::enums::Message::Message(m) => m.media.as_ref(),
249 _ => None,
250 }
251 }
252
253 pub fn entities(&self) -> Option<&Vec<tl::enums::MessageEntity>> {
255 match &self.raw {
256 tl::enums::Message::Message(m) => m.entities.as_ref(),
257 _ => None,
258 }
259 }
260
261 pub fn grouped_id(&self) -> Option<i64> {
263 match &self.raw {
264 tl::enums::Message::Message(m) => m.grouped_id,
265 _ => None,
266 }
267 }
268
269 pub fn from_scheduled(&self) -> bool {
271 match &self.raw {
272 tl::enums::Message::Message(m) => m.from_scheduled,
273 _ => false,
274 }
275 }
276
277 pub fn edit_hide(&self) -> bool {
279 match &self.raw {
280 tl::enums::Message::Message(m) => m.edit_hide,
281 _ => false,
282 }
283 }
284
285 pub fn media_unread(&self) -> bool {
287 match &self.raw {
288 tl::enums::Message::Message(m) => m.media_unread,
289 tl::enums::Message::Service(m) => m.media_unread,
290 _ => false,
291 }
292 }
293
294 pub fn via_bot_id(&self) -> Option<i64> {
296 match &self.raw {
297 tl::enums::Message::Message(m) => m.via_bot_id,
298 _ => None,
299 }
300 }
301
302 pub fn post_author(&self) -> Option<&str> {
304 match &self.raw {
305 tl::enums::Message::Message(m) => m.post_author.as_deref(),
306 _ => None,
307 }
308 }
309
310 pub fn reaction_count(&self) -> i32 {
312 match &self.raw {
313 tl::enums::Message::Message(m) => m
314 .reactions
315 .as_ref()
316 .map(|r| match r {
317 tl::enums::MessageReactions::MessageReactions(x) => x
318 .results
319 .iter()
320 .map(|res| match res {
321 tl::enums::ReactionCount::ReactionCount(c) => c.count,
322 })
323 .sum(),
324 })
325 .unwrap_or(0),
326 _ => 0,
327 }
328 }
329
330 pub fn restriction_reason(&self) -> Option<&Vec<tl::enums::RestrictionReason>> {
332 match &self.raw {
333 tl::enums::Message::Message(m) => m.restriction_reason.as_ref(),
334 _ => None,
335 }
336 }
337
338 pub fn reply_markup(&self) -> Option<&tl::enums::ReplyMarkup> {
340 match &self.raw {
341 tl::enums::Message::Message(m) => m.reply_markup.as_ref(),
342 _ => None,
343 }
344 }
345
346 pub fn forward_header(&self) -> Option<&tl::enums::MessageFwdHeader> {
348 match &self.raw {
349 tl::enums::Message::Message(m) => m.fwd_from.as_ref(),
350 _ => None,
351 }
352 }
353
354 pub fn noforwards(&self) -> bool {
356 match &self.raw {
357 tl::enums::Message::Message(m) => m.noforwards,
358 _ => false,
359 }
360 }
361
362 pub fn markdown_text(&self) -> Option<String> {
366 let text = self.text()?;
367 let entities = self.entities().map(|e| e.as_slice()).unwrap_or(&[]);
368 Some(crate::parsers::generate_markdown(text, entities))
369 }
370
371 pub fn html_text(&self) -> Option<String> {
375 let text = self.text()?;
376 let entities = self.entities().map(|e| e.as_slice()).unwrap_or(&[]);
377 Some(crate::parsers::generate_html(text, entities))
378 }
379
380 pub fn action(&self) -> Option<&tl::enums::MessageAction> {
383 match &self.raw {
384 tl::enums::Message::Service(m) => Some(&m.action),
385 _ => None,
386 }
387 }
388
389 pub fn photo(&self) -> Option<crate::media::Photo> {
393 crate::media::Photo::from_media(self.media()?)
394 }
395
396 pub fn document(&self) -> Option<crate::media::Document> {
400 crate::media::Document::from_media(self.media()?)
401 }
402
403 pub async fn reply(&self, text: impl Into<String>) -> Result<IncomingMessage, Error> {
418 let client = self.require_client("reply")?.clone();
419 self.reply_with(&client, text).await
420 }
421
422 pub async fn reply_with(
426 &self,
427 client: &Client,
428 text: impl Into<String>,
429 ) -> Result<IncomingMessage, Error> {
430 let peer = match self.peer_id() {
431 Some(p) => p.clone(),
432 None => return Err(Error::Deserialize("cannot reply: unknown peer".into())),
433 };
434 let msg_id = self.id();
435 client
436 .send_message_to_peer_ex(
437 peer,
438 &crate::InputMessage::text(text.into()).reply_to(Some(msg_id)),
439 )
440 .await
441 }
442
443 pub async fn reply_ex(&self, msg: crate::InputMessage) -> Result<IncomingMessage, Error> {
445 let client = self.require_client("reply_ex")?.clone();
446 self.reply_ex_with(&client, msg).await
447 }
448
449 pub async fn reply_ex_with(
451 &self,
452 client: &Client,
453 msg: crate::InputMessage,
454 ) -> Result<IncomingMessage, Error> {
455 let peer = self
456 .peer_id()
457 .cloned()
458 .ok_or_else(|| Error::Deserialize("cannot reply_ex: unknown peer".into()))?;
459 client
460 .send_message_to_peer_ex(peer, &msg.reply_to(Some(self.id())))
461 .await
462 }
463
464 pub async fn respond(&self, text: impl Into<String>) -> Result<IncomingMessage, Error> {
468 let client = self.require_client("respond")?.clone();
469 self.respond_with(&client, text).await
470 }
471
472 pub async fn respond_with(
474 &self,
475 client: &Client,
476 text: impl Into<String>,
477 ) -> Result<IncomingMessage, Error> {
478 let peer = self
479 .peer_id()
480 .cloned()
481 .ok_or_else(|| Error::Deserialize("cannot respond: unknown peer".into()))?;
482 client
483 .send_message_to_peer_ex(peer, &crate::InputMessage::text(text.into()))
484 .await
485 }
486
487 pub async fn respond_ex(&self, msg: crate::InputMessage) -> Result<IncomingMessage, Error> {
489 let client = self.require_client("respond_ex")?.clone();
490 self.respond_ex_with(&client, msg).await
491 }
492
493 pub async fn respond_ex_with(
495 &self,
496 client: &Client,
497 msg: crate::InputMessage,
498 ) -> Result<IncomingMessage, Error> {
499 let peer = self
500 .peer_id()
501 .cloned()
502 .ok_or_else(|| Error::Deserialize("cannot respond_ex: unknown peer".into()))?;
503 client.send_message_to_peer_ex(peer, &msg).await
504 }
505
506 pub async fn edit(&self, new_text: impl Into<String>) -> Result<(), Error> {
510 let client = self.require_client("edit")?.clone();
511 self.edit_with(&client, new_text).await
512 }
513
514 pub async fn edit_with(
516 &self,
517 client: &Client,
518 new_text: impl Into<String>,
519 ) -> Result<(), Error> {
520 let peer = self
521 .peer_id()
522 .cloned()
523 .ok_or_else(|| Error::Deserialize("cannot edit: unknown peer".into()))?;
524 client
525 .edit_message(peer, self.id(), new_text.into().as_str())
526 .await
527 }
528
529 pub async fn delete(&self) -> Result<(), Error> {
533 let client = self.require_client("delete")?.clone();
534 self.delete_with(&client).await
535 }
536
537 pub async fn delete_with(&self, client: &Client) -> Result<(), Error> {
539 client.delete_messages(vec![self.id()], true).await
540 }
541
542 pub async fn mark_as_read(&self) -> Result<(), Error> {
546 let client = self.require_client("mark_as_read")?.clone();
547 self.mark_as_read_with(&client).await
548 }
549
550 pub async fn mark_as_read_with(&self, client: &Client) -> Result<(), Error> {
552 let peer = self
553 .peer_id()
554 .cloned()
555 .ok_or_else(|| Error::Deserialize("cannot mark_as_read: unknown peer".into()))?;
556 client.mark_as_read(peer).await
557 }
558
559 pub async fn pin(&self) -> Result<(), Error> {
563 let client = self.require_client("pin")?.clone();
564 self.pin_with(&client).await
565 }
566
567 pub async fn pin_with(&self, client: &Client) -> Result<(), Error> {
569 let peer = self
570 .peer_id()
571 .cloned()
572 .ok_or_else(|| Error::Deserialize("cannot pin: unknown peer".into()))?;
573 client
574 .pin_message(peer, self.id(), true, false, false)
575 .await
576 }
577
578 pub async fn unpin(&self) -> Result<(), Error> {
582 let client = self.require_client("unpin")?.clone();
583 self.unpin_with(&client).await
584 }
585
586 pub async fn unpin_with(&self, client: &Client) -> Result<(), Error> {
588 let peer = self
589 .peer_id()
590 .cloned()
591 .ok_or_else(|| Error::Deserialize("cannot unpin: unknown peer".into()))?;
592 client.unpin_message(peer, self.id()).await
593 }
594
595 pub async fn forward_to(
601 &self,
602 destination: impl Into<crate::PeerRef>,
603 ) -> Result<IncomingMessage, Error> {
604 let client = self.require_client("forward_to")?.clone();
605 self.forward_to_with(&client, destination).await
606 }
607
608 pub async fn forward_to_with(
612 &self,
613 client: &Client,
614 destination: impl Into<crate::PeerRef>,
615 ) -> Result<IncomingMessage, Error> {
616 let src = self
617 .peer_id()
618 .cloned()
619 .ok_or_else(|| Error::Deserialize("cannot forward: unknown source peer".into()))?;
620 client
621 .forward_messages_returning(destination, &[self.id()], src)
622 .await
623 .and_then(|v| {
624 v.into_iter()
625 .next()
626 .ok_or_else(|| Error::Deserialize("forward returned no message".into()))
627 })
628 }
629
630 pub async fn refetch(&mut self) -> Result<(), Error> {
637 let client = self.require_client("refetch")?.clone();
638 self.refetch_with(&client).await
639 }
640
641 pub async fn refetch_with(&mut self, client: &Client) -> Result<(), Error> {
643 let peer = self
644 .peer_id()
645 .cloned()
646 .ok_or_else(|| Error::Deserialize("cannot refetch: unknown peer".into()))?;
647 let mut msgs = client.get_messages_by_id(peer, &[self.id()]).await?;
648 match msgs.pop() {
649 Some(m) => {
650 self.raw = m.raw;
651 Ok(())
652 }
653 None => Err(Error::Deserialize(
654 "refetch: message not found (deleted?)".into(),
655 )),
656 }
657 }
658
659 pub async fn download_media(&self, path: impl AsRef<std::path::Path>) -> Result<bool, Error> {
663 let client = self.require_client("download_media")?.clone();
664 self.download_media_with(&client, path).await
665 }
666
667 pub async fn download_media_with(
669 &self,
670 client: &Client,
671 path: impl AsRef<std::path::Path>,
672 ) -> Result<bool, Error> {
673 if let Some(loc) = crate::media::download_location_from_media(self.media()) {
674 client.download_media_to_file(loc, path).await?;
675 Ok(true)
676 } else {
677 Ok(false)
678 }
679 }
680
681 pub async fn react(
694 &self,
695 reactions: impl Into<crate::reactions::InputReactions>,
696 ) -> Result<(), Error> {
697 let client = self.require_client("react")?.clone();
698 self.react_with(&client, reactions).await
699 }
700
701 pub async fn react_with(
703 &self,
704 client: &Client,
705 reactions: impl Into<crate::reactions::InputReactions>,
706 ) -> Result<(), Error> {
707 let peer = self
708 .peer_id()
709 .cloned()
710 .ok_or_else(|| Error::Deserialize("cannot react: unknown peer".into()))?;
711 client.send_reaction(peer, self.id(), reactions).await
712 }
713
714 pub async fn get_reply(&self) -> Result<Option<IncomingMessage>, Error> {
718 let client = self.require_client("get_reply")?.clone();
719 self.get_reply_with(&client).await
720 }
721
722 pub async fn get_reply_with(&self, client: &Client) -> Result<Option<IncomingMessage>, Error> {
724 client.get_reply_to_message(self).await
725 }
726
727 pub fn sender_user_id(&self) -> Option<i64> {
733 match self.sender_id()? {
734 tl::enums::Peer::User(u) => Some(u.user_id),
735 _ => None,
736 }
737 }
738
739 pub fn sender_chat_id(&self) -> Option<i64> {
741 match self.sender_id()? {
742 tl::enums::Peer::Chat(c) => Some(c.chat_id),
743 tl::enums::Peer::Channel(c) => Some(c.channel_id),
744 _ => None,
745 }
746 }
747
748 pub async fn sender_user(&self) -> Result<Option<crate::types::User>, Error> {
753 let uid = match self.sender_user_id() {
754 Some(id) => id,
755 None => return Ok(None),
756 };
757 let client = self.require_client("sender_user")?.clone();
758 let users = client.get_users_by_id(&[uid]).await?;
759 Ok(users.into_iter().next().flatten())
760 }
761}
762
763#[derive(Debug, Clone)]
767pub struct MessageDeletion {
768 pub message_ids: Vec<i32>,
770 pub channel_id: Option<i64>,
772}
773
774impl MessageDeletion {
775 pub fn into_messages(self) -> Vec<i32> {
777 self.message_ids
778 }
779}
780
781#[derive(Debug, Clone)]
785pub struct CallbackQuery {
786 pub query_id: i64,
787 pub user_id: i64,
788 pub message_id: Option<i32>,
789 pub chat_instance: i64,
790 pub data_raw: Option<Vec<u8>>,
792 pub game_short_name: Option<String>,
794 pub chat_peer: Option<tl::enums::Peer>,
797 pub inline_msg_id: Option<tl::enums::InputBotInlineMessageId>,
799}
800
801impl CallbackQuery {
802 pub fn data(&self) -> Option<&str> {
804 self.data_raw
805 .as_ref()
806 .and_then(|d| std::str::from_utf8(d).ok())
807 }
808
809 pub fn answer(&self) -> Answer<'_> {
823 Answer {
824 query_id: self.query_id,
825 message: None,
826 alert: false,
827 url: None,
828 cache_time: 0,
829 _marker: std::marker::PhantomData,
830 }
831 }
832
833 pub async fn answer_flat(&self, client: &Client, text: Option<&str>) -> Result<(), Error> {
835 client
836 .answer_callback_query(self.query_id, text, false)
837 .await
838 .map(|_| ())
839 }
840
841 pub async fn answer_alert(&self, client: &Client, text: &str) -> Result<(), Error> {
843 client
844 .answer_callback_query(self.query_id, Some(text), true)
845 .await
846 .map(|_| ())
847 }
848}
849
850pub struct Answer<'a> {
852 query_id: i64,
853 message: Option<String>,
854 alert: bool,
855 url: Option<String>,
856 cache_time: i32,
857 _marker: std::marker::PhantomData<&'a ()>,
858}
859
860impl<'a> Answer<'a> {
861 pub fn text<S: Into<String>>(mut self, text: S) -> Self {
863 self.message = Some(text.into());
864 self.alert = false;
865 self
866 }
867
868 pub fn alert<S: Into<String>>(mut self, text: S) -> Self {
870 self.message = Some(text.into());
871 self.alert = true;
872 self
873 }
874
875 pub fn url<S: Into<String>>(mut self, url: S) -> Self {
877 self.url = Some(url.into());
878 self
879 }
880
881 pub fn cache_time(mut self, duration: std::time::Duration) -> Self {
883 self.cache_time = duration.as_secs().min(i32::MAX as u64) as i32;
884 self
885 }
886
887 pub async fn send(self, client: &Client) -> Result<(), Error> {
889 let req = tl::functions::messages::SetBotCallbackAnswer {
890 alert: self.alert,
891 query_id: self.query_id,
892 message: self.message,
893 url: self.url,
894 cache_time: self.cache_time,
895 };
896 client.rpc_call_raw_pub(&req).await.map(|_| ())
897 }
898}
899
900#[derive(Debug, Clone)]
904pub struct InlineQuery {
905 pub query_id: i64,
906 pub user_id: i64,
907 pub query: String,
908 pub offset: String,
909 pub peer: Option<tl::enums::Peer>,
911}
912
913impl InlineQuery {
914 pub fn query(&self) -> &str {
916 &self.query
917 }
918}
919
920#[derive(Debug, Clone)]
924pub struct InlineSend {
925 pub user_id: i64,
926 pub query: String,
927 pub id: String,
928 pub msg_id: Option<tl::enums::InputBotInlineMessageId>,
930}
931
932impl InlineSend {
933 pub async fn edit_message(
948 &self,
949 client: &Client,
950 new_text: &str,
951 reply_markup: Option<tl::enums::ReplyMarkup>,
952 ) -> Result<bool, Error> {
953 let msg_id =
954 match self.msg_id.clone() {
955 Some(id) => id,
956 None => return Err(Error::Deserialize(
957 "InlineSend::edit_message: msg_id is None (bot_inline_send had no peer_type)"
958 .into(),
959 )),
960 };
961 let req = tl::functions::messages::EditInlineBotMessage {
962 no_webpage: false,
963 invert_media: false,
964 id: msg_id,
965 message: Some(new_text.to_string()),
966 media: None,
967 reply_markup,
968 entities: None,
969 };
970 let body = client.rpc_call_raw(&req).await?;
971 Ok(!body.is_empty())
973 }
974}
975
976#[derive(Debug, Clone)]
980pub struct RawUpdate {
981 pub constructor_id: u32,
983}
984
985#[derive(Debug, Clone)]
1001pub struct UserStatusUpdate {
1002 pub user_id: i64,
1004 pub status: tl::enums::UserStatus,
1006}
1007
1008#[derive(Debug, Clone)]
1024pub struct ChatActionUpdate {
1025 pub peer: tl::enums::Peer,
1028 pub user_id: i64,
1030 pub action: tl::enums::SendMessageAction,
1032}
1033
1034#[non_exhaustive]
1036#[derive(Debug, Clone)]
1037pub enum Update {
1038 NewMessage(IncomingMessage),
1040 MessageEdited(IncomingMessage),
1042 MessageDeleted(MessageDeletion),
1044 CallbackQuery(CallbackQuery),
1046 InlineQuery(InlineQuery),
1048 InlineSend(InlineSend),
1050 UserStatus(UserStatusUpdate),
1052 UserTyping(ChatActionUpdate),
1054 Raw(RawUpdate),
1056}
1057
1058#[allow(dead_code)]
1061const ID_UPDATES_TOO_LONG: u32 = 0xe317af7e;
1062#[allow(dead_code)]
1063const ID_UPDATE_SHORT_MESSAGE: u32 = 0x313bc7f8;
1064#[allow(dead_code)]
1065const ID_UPDATE_SHORT_CHAT_MSG: u32 = 0x4d6deea5;
1066#[allow(dead_code)]
1067const ID_UPDATE_SHORT: u32 = 0x78d4dec1;
1068#[allow(dead_code)]
1069const ID_UPDATES: u32 = 0x74ae4240;
1070#[allow(dead_code)]
1071const ID_UPDATES_COMBINED: u32 = 0x725b04c3;
1072#[allow(dead_code)]
1073const ID_UPDATE_SHORT_SENT_MSG: u32 = 0x9015e101;
1074
1075#[allow(dead_code)]
1079pub(crate) fn parse_updates(bytes: &[u8]) -> Vec<Update> {
1080 if bytes.len() < 4 {
1081 return vec![];
1082 }
1083 let cid = u32::from_le_bytes(bytes[..4].try_into().unwrap());
1084
1085 match cid {
1086 ID_UPDATES_TOO_LONG => {
1087 tracing::warn!(
1088 "[layer] updatesTooLong: call client.get_difference() to recover missed updates"
1089 );
1090 vec![]
1091 }
1092
1093 ID_UPDATE_SHORT_MESSAGE => {
1094 let mut cur = Cursor::from_slice(&bytes[4..]); match tl::types::UpdateShortMessage::deserialize(&mut cur) {
1096 Ok(m) => vec![Update::NewMessage(make_short_dm(m))],
1097 Err(e) => {
1098 tracing::debug!(
1099 "[layer] updateShortMessage parse error (unknown constructor or newer layer): {e}"
1100 );
1101 vec![]
1102 }
1103 }
1104 }
1105
1106 ID_UPDATE_SHORT_CHAT_MSG => {
1107 let mut cur = Cursor::from_slice(&bytes[4..]); match tl::types::UpdateShortChatMessage::deserialize(&mut cur) {
1109 Ok(m) => vec![Update::NewMessage(make_short_chat(m))],
1110 Err(e) => {
1111 tracing::debug!(
1112 "[layer] updateShortChatMessage parse error (unknown constructor or newer layer): {e}"
1113 );
1114 vec![]
1115 }
1116 }
1117 }
1118
1119 ID_UPDATE_SHORT => {
1120 let mut cur = Cursor::from_slice(&bytes[4..]); match tl::types::UpdateShort::deserialize(&mut cur) {
1122 Ok(m) => from_single_update(m.update),
1123 Err(e) => {
1124 tracing::debug!(
1125 "[layer] updateShort parse error (unknown constructor or newer layer): {e}"
1126 );
1127 vec![]
1128 }
1129 }
1130 }
1131
1132 ID_UPDATES => {
1133 let mut cur = Cursor::from_slice(bytes);
1134 match tl::enums::Updates::deserialize(&mut cur) {
1135 Ok(tl::enums::Updates::Updates(u)) => {
1136 u.updates.into_iter().flat_map(from_single_update).collect()
1137 }
1138 Err(e) => {
1139 tracing::debug!(
1140 "[layer] Updates parse error (unknown constructor or newer layer): {e}"
1141 );
1142 vec![]
1143 }
1144 _ => vec![],
1145 }
1146 }
1147
1148 ID_UPDATES_COMBINED => {
1149 let mut cur = Cursor::from_slice(bytes);
1150 match tl::enums::Updates::deserialize(&mut cur) {
1151 Ok(tl::enums::Updates::Combined(u)) => {
1152 u.updates.into_iter().flat_map(from_single_update).collect()
1153 }
1154 Err(e) => {
1155 tracing::debug!(
1156 "[layer] UpdatesCombined parse error (unknown constructor or newer layer): {e}"
1157 );
1158 vec![]
1159 }
1160 _ => vec![],
1161 }
1162 }
1163
1164 ID_UPDATE_SHORT_SENT_MSG => vec![],
1168
1169 _ => vec![],
1170 }
1171}
1172
1173pub fn from_single_update_pub(upd: tl::enums::Update) -> Vec<Update> {
1175 from_single_update(upd)
1176}
1177
1178fn from_single_update(upd: tl::enums::Update) -> Vec<Update> {
1180 use tl::enums::Update::*;
1181 match upd {
1182 NewMessage(u) => vec![Update::NewMessage(IncomingMessage::from_raw(u.message))],
1183 NewChannelMessage(u) => vec![Update::NewMessage(IncomingMessage::from_raw(u.message))],
1184 EditMessage(u) => vec![Update::MessageEdited(IncomingMessage::from_raw(u.message))],
1185 EditChannelMessage(u) => vec![Update::MessageEdited(IncomingMessage::from_raw(u.message))],
1186 DeleteMessages(u) => vec![Update::MessageDeleted(MessageDeletion {
1187 message_ids: u.messages,
1188 channel_id: None,
1189 })],
1190 DeleteChannelMessages(u) => vec![Update::MessageDeleted(MessageDeletion {
1191 message_ids: u.messages,
1192 channel_id: Some(u.channel_id),
1193 })],
1194 BotCallbackQuery(u) => vec![Update::CallbackQuery(CallbackQuery {
1195 query_id: u.query_id,
1196 user_id: u.user_id,
1197 message_id: Some(u.msg_id),
1198 chat_instance: u.chat_instance,
1199 data_raw: u.data,
1200 game_short_name: u.game_short_name,
1201 chat_peer: Some(u.peer),
1202 inline_msg_id: None,
1203 })],
1204 InlineBotCallbackQuery(u) => vec![Update::CallbackQuery(CallbackQuery {
1205 query_id: u.query_id,
1206 user_id: u.user_id,
1207 message_id: None,
1208 chat_instance: u.chat_instance,
1209 data_raw: u.data,
1210 game_short_name: u.game_short_name,
1211 chat_peer: None,
1212 inline_msg_id: Some(u.msg_id),
1213 })],
1214 BotInlineQuery(u) => vec![Update::InlineQuery(InlineQuery {
1215 query_id: u.query_id,
1216 user_id: u.user_id,
1217 query: u.query,
1218 offset: u.offset,
1219 peer: None,
1220 })],
1221 BotInlineSend(u) => vec![Update::InlineSend(InlineSend {
1222 user_id: u.user_id,
1223 query: u.query,
1224 id: u.id,
1225 msg_id: u.msg_id,
1226 })],
1227 UserStatus(u) => vec![Update::UserStatus(UserStatusUpdate {
1229 user_id: u.user_id,
1230 status: u.status,
1231 })],
1232 UserTyping(u) => vec![Update::UserTyping(ChatActionUpdate {
1234 peer: tl::enums::Peer::User(tl::types::PeerUser { user_id: u.user_id }),
1235 user_id: u.user_id,
1236 action: u.action,
1237 })],
1238 ChatUserTyping(u) => vec![Update::UserTyping(ChatActionUpdate {
1240 peer: tl::enums::Peer::Chat(tl::types::PeerChat { chat_id: u.chat_id }),
1241 user_id: match u.from_id {
1242 tl::enums::Peer::User(ref p) => p.user_id,
1243 tl::enums::Peer::Chat(ref p) => p.chat_id,
1244 tl::enums::Peer::Channel(ref p) => p.channel_id,
1245 },
1246 action: u.action,
1247 })],
1248 ChannelUserTyping(u) => vec![Update::UserTyping(ChatActionUpdate {
1250 peer: tl::enums::Peer::Channel(tl::types::PeerChannel {
1251 channel_id: u.channel_id,
1252 }),
1253 user_id: match u.from_id {
1254 tl::enums::Peer::User(ref p) => p.user_id,
1255 tl::enums::Peer::Chat(ref p) => p.chat_id,
1256 tl::enums::Peer::Channel(ref p) => p.channel_id,
1257 },
1258 action: u.action,
1259 })],
1260 other => {
1261 let cid = tl_constructor_id(&other);
1262 vec![Update::Raw(RawUpdate {
1263 constructor_id: cid,
1264 })]
1265 }
1266 }
1267}
1268
1269fn tl_constructor_id(upd: &tl::enums::Update) -> u32 {
1271 use tl::enums::Update::*;
1272 match upd {
1273 AttachMenuBots => 0x17b7a20b,
1274 AutoSaveSettings => 0xec05b097,
1275 BotBusinessConnect(_) => 0x8ae5c97a,
1276 BotCallbackQuery(_) => 0xb9cfc48d,
1277 BotChatBoost(_) => 0x904dd49c,
1278 BotChatInviteRequester(_) => 0x11dfa986,
1279 BotCommands(_) => 0x4d712f2e,
1280 BotDeleteBusinessMessage(_) => 0xa02a982e,
1281 BotEditBusinessMessage(_) => 0x7df587c,
1282 BotInlineQuery(_) => 0x496f379c,
1283 BotInlineSend(_) => 0x12f12a07,
1284 BotMenuButton(_) => 0x14b85813,
1285 BotMessageReaction(_) => 0xac21d3ce,
1286 BotMessageReactions(_) => 0x9cb7759,
1287 BotNewBusinessMessage(_) => 0x9ddb347c,
1288 BotPrecheckoutQuery(_) => 0x8caa9a96,
1289 BotPurchasedPaidMedia(_) => 0x283bd312,
1290 BotShippingQuery(_) => 0xb5aefd7d,
1291 BotStopped(_) => 0xc4870a49,
1292 BotWebhookJson(_) => 0x8317c0c3,
1293 BotWebhookJsonquery(_) => 0x9b9240a6,
1294 BusinessBotCallbackQuery(_) => 0x1ea2fda7,
1295 Channel(_) => 0x635b4c09,
1296 ChannelAvailableMessages(_) => 0xb23fc698,
1297 ChannelMessageForwards(_) => 0xd29a27f4,
1298 ChannelMessageViews(_) => 0xf226ac08,
1299 ChannelParticipant(_) => 0x985d3abb,
1300 ChannelReadMessagesContents(_) => 0x25f324f7,
1301 ChannelTooLong(_) => 0x108d941f,
1302 ChannelUserTyping(_) => 0x8c88c923,
1303 ChannelViewForumAsMessages(_) => 0x7b68920,
1304 ChannelWebPage(_) => 0x2f2ba99f,
1305 Chat(_) => 0xf89a6a4e,
1306 ChatDefaultBannedRights(_) => 0x54c01850,
1307 ChatParticipant(_) => 0xd087663a,
1308 ChatParticipantAdd(_) => 0x3dda5451,
1309 ChatParticipantAdmin(_) => 0xd7ca61a2,
1310 ChatParticipantDelete(_) => 0xe32f3d77,
1311 ChatParticipants(_) => 0x7761198,
1312 ChatUserTyping(_) => 0x83487af0,
1313 Config => 0xa229dd06,
1314 ContactsReset => 0x7084a7be,
1315 DcOptions(_) => 0x8e5e9873,
1316 DeleteChannelMessages(_) => 0xc32d5b12,
1317 DeleteGroupCallMessages(_) => 0x3e85e92c,
1318 DeleteMessages(_) => 0xa20db0e5,
1319 DeleteQuickReply(_) => 0x53e6f1ec,
1320 DeleteQuickReplyMessages(_) => 0x566fe7cd,
1321 DeleteScheduledMessages(_) => 0xf2a71983,
1322 DialogFilter(_) => 0x26ffde7d,
1323 DialogFilterOrder(_) => 0xa5d72105,
1324 DialogFilters => 0x3504914f,
1325 DialogPinned(_) => 0x6e6fe51c,
1326 DialogUnreadMark(_) => 0xb658f23e,
1327 DraftMessage(_) => 0xedfc111e,
1328 EditChannelMessage(_) => 0x1b3f4df7,
1329 EditMessage(_) => 0xe40370a3,
1330 EmojiGameInfo(_) => 0xfb9c547a,
1331 EncryptedChatTyping(_) => 0x1710f156,
1332 EncryptedMessagesRead(_) => 0x38fe25b7,
1333 Encryption(_) => 0xb4a2e88d,
1334 FavedStickers => 0xe511996d,
1335 FolderPeers(_) => 0x19360dc0,
1336 GeoLiveViewed(_) => 0x871fb939,
1337 GroupCall(_) => 0x9d2216e0,
1338 GroupCallChainBlocks(_) => 0xa477288f,
1339 GroupCallConnection(_) => 0xb783982,
1340 GroupCallEncryptedMessage(_) => 0xc957a766,
1341 GroupCallMessage(_) => 0xd8326f0d,
1342 GroupCallParticipants(_) => 0xf2ebdb4e,
1343 InlineBotCallbackQuery(_) => 0x691e9052,
1344 LangPack(_) => 0x56022f4d,
1345 LangPackTooLong(_) => 0x46560264,
1346 LoginToken => 0x564fe691,
1347 MessageExtendedMedia(_) => 0xd5a41724,
1348 MessageId(_) => 0x4e90bfd6,
1349 MessagePoll(_) => 0xaca1657b,
1350 MessagePollVote(_) => 0x24f40e77,
1351 MessageReactions(_) => 0x1e297bfa,
1352 MonoForumNoPaidException(_) => 0x9f812b08,
1353 MoveStickerSetToTop(_) => 0x86fccf85,
1354 NewAuthorization(_) => 0x8951abef,
1355 NewChannelMessage(_) => 0x62ba04d9,
1356 NewEncryptedMessage(_) => 0x12bcbd9a,
1357 NewMessage(_) => 0x1f2b0afd,
1358 NewQuickReply(_) => 0xf53da717,
1359 NewScheduledMessage(_) => 0x39a51dfb,
1360 NewStickerSet(_) => 0x688a30aa,
1361 NewStoryReaction(_) => 0x1824e40b,
1362 NotifySettings(_) => 0xbec268ef,
1363 PaidReactionPrivacy(_) => 0x8b725fce,
1364 PeerBlocked(_) => 0xebe07752,
1365 PeerHistoryTtl(_) => 0xbb9bb9a5,
1366 PeerLocated(_) => 0xb4afcfb0,
1367 PeerSettings(_) => 0x6a7e7366,
1368 PeerWallpaper(_) => 0xae3f101d,
1369 PendingJoinRequests(_) => 0x7063c3db,
1370 PhoneCall(_) => 0xab0f6b1e,
1371 PhoneCallSignalingData(_) => 0x2661bf09,
1372 PinnedChannelMessages(_) => 0x5bb98608,
1373 PinnedDialogs(_) => 0xfa0f3ca2,
1374 PinnedForumTopic(_) => 0x683b2c52,
1375 PinnedForumTopics(_) => 0xdef143d0,
1376 PinnedMessages(_) => 0xed85eab5,
1377 PinnedSavedDialogs(_) => 0x686c85a6,
1378 Privacy(_) => 0xee3b272a,
1379 PtsChanged => 0x3354678f,
1380 QuickReplies(_) => 0xf9470ab2,
1381 QuickReplyMessage(_) => 0x3e050d0f,
1382 ReadChannelDiscussionInbox(_) => 0xd6b19546,
1383 ReadChannelDiscussionOutbox(_) => 0x695c9e7c,
1384 ReadChannelInbox(_) => 0x922e6e10,
1385 ReadChannelOutbox(_) => 0xb75f99a9,
1386 ReadFeaturedEmojiStickers => 0xfb4c496c,
1387 ReadFeaturedStickers => 0x571d2742,
1388 ReadHistoryInbox(_) => 0x9e84bc99,
1389 ReadHistoryOutbox(_) => 0x2f2f21bf,
1390 ReadMessagesContents(_) => 0xf8227181,
1391 ReadMonoForumInbox(_) => 0x77b0e372,
1392 ReadMonoForumOutbox(_) => 0xa4a79376,
1393 ReadStories(_) => 0xf74e932b,
1394 RecentEmojiStatuses => 0x30f443db,
1395 RecentReactions => 0x6f7863f4,
1396 RecentStickers => 0x9a422c20,
1397 SavedDialogPinned(_) => 0xaeaf9e74,
1398 SavedGifs => 0x9375341e,
1399 SavedReactionTags => 0x39c67432,
1400 SavedRingtones => 0x74d8be99,
1401 SentPhoneCode(_) => 0x504aa18f,
1402 SentStoryReaction(_) => 0x7d627683,
1403 ServiceNotification(_) => 0xebe46819,
1404 SmsJob(_) => 0xf16269d4,
1405 StarGiftAuctionState(_) => 0x48e246c2,
1406 StarGiftAuctionUserState(_) => 0xdc58f31e,
1407 StarGiftCraftFail => 0xac072444,
1408 StarsBalance(_) => 0x4e80a379,
1409 StarsRevenueStatus(_) => 0xa584b019,
1410 StickerSets(_) => 0x31c24808,
1411 StickerSetsOrder(_) => 0xbb2d201,
1412 StoriesStealthMode(_) => 0x2c084dc1,
1413 Story(_) => 0x75b3b798,
1414 StoryId(_) => 0x1bf335b9,
1415 Theme(_) => 0x8216fba3,
1416 TranscribedAudio(_) => 0x84cd5a,
1417 User(_) => 0x20529438,
1418 UserEmojiStatus(_) => 0x28373599,
1419 UserName(_) => 0xa7848924,
1420 UserPhone(_) => 0x5492a13,
1421 UserStatus(_) => 0xe5bdf8de,
1422 UserTyping(_) => 0x2a17bf5c,
1423 WebPage(_) => 0x7f891213,
1424 WebViewResultSent(_) => 0x1592b79d,
1425 ChatParticipantRank(_) => 0xbd8367b9,
1426 ManagedBot(_) => 0x4880ed9a,
1427 }
1428}
1429
1430pub(crate) fn make_short_dm(m: tl::types::UpdateShortMessage) -> IncomingMessage {
1433 let msg = tl::types::Message {
1434 out: m.out,
1435 mentioned: m.mentioned,
1436 media_unread: m.media_unread,
1437 silent: m.silent,
1438 post: false,
1439 from_scheduled: false,
1440 legacy: false,
1441 edit_hide: false,
1442 pinned: false,
1443 noforwards: false,
1444 invert_media: false,
1445 offline: false,
1446 video_processing_pending: false,
1447 id: m.id,
1448 from_id: Some(tl::enums::Peer::User(tl::types::PeerUser {
1449 user_id: m.user_id,
1450 })),
1451 peer_id: tl::enums::Peer::User(tl::types::PeerUser { user_id: m.user_id }),
1452 saved_peer_id: None,
1453 fwd_from: m.fwd_from,
1454 via_bot_id: m.via_bot_id,
1455 via_business_bot_id: None,
1456 reply_to: m.reply_to,
1457 date: m.date,
1458 message: m.message,
1459 media: None,
1460 reply_markup: None,
1461 entities: m.entities,
1462 views: None,
1463 forwards: None,
1464 replies: None,
1465 edit_date: None,
1466 post_author: None,
1467 grouped_id: None,
1468 reactions: None,
1469 restriction_reason: None,
1470 ttl_period: None,
1471 quick_reply_shortcut_id: None,
1472 effect: None,
1473 factcheck: None,
1474 report_delivery_until_date: None,
1475 paid_message_stars: None,
1476 suggested_post: None,
1477 from_rank: None,
1478 from_boosts_applied: None,
1479 paid_suggested_post_stars: false,
1480 paid_suggested_post_ton: false,
1481 schedule_repeat_period: None,
1482 summary_from_language: None,
1483 };
1484 IncomingMessage {
1485 raw: tl::enums::Message::Message(msg),
1486 client: None,
1487 }
1488}
1489
1490pub(crate) fn make_short_chat(m: tl::types::UpdateShortChatMessage) -> IncomingMessage {
1491 let msg = tl::types::Message {
1492 out: m.out,
1493 mentioned: m.mentioned,
1494 media_unread: m.media_unread,
1495 silent: m.silent,
1496 post: false,
1497 from_scheduled: false,
1498 legacy: false,
1499 edit_hide: false,
1500 pinned: false,
1501 noforwards: false,
1502 invert_media: false,
1503 offline: false,
1504 video_processing_pending: false,
1505 id: m.id,
1506 from_id: Some(tl::enums::Peer::User(tl::types::PeerUser {
1507 user_id: m.from_id,
1508 })),
1509 peer_id: tl::enums::Peer::Chat(tl::types::PeerChat { chat_id: m.chat_id }),
1510 saved_peer_id: None,
1511 fwd_from: m.fwd_from,
1512 via_bot_id: m.via_bot_id,
1513 via_business_bot_id: None,
1514 reply_to: m.reply_to,
1515 date: m.date,
1516 message: m.message,
1517 media: None,
1518 reply_markup: None,
1519 entities: m.entities,
1520 views: None,
1521 forwards: None,
1522 replies: None,
1523 edit_date: None,
1524 post_author: None,
1525 grouped_id: None,
1526 reactions: None,
1527 restriction_reason: None,
1528 ttl_period: None,
1529 quick_reply_shortcut_id: None,
1530 effect: None,
1531 factcheck: None,
1532 report_delivery_until_date: None,
1533 paid_message_stars: None,
1534 suggested_post: None,
1535 from_rank: None,
1536 from_boosts_applied: None,
1537 paid_suggested_post_stars: false,
1538 paid_suggested_post_ton: false,
1539 schedule_repeat_period: None,
1540 summary_from_language: None,
1541 };
1542 IncomingMessage {
1543 raw: tl::enums::Message::Message(msg),
1544 client: None,
1545 }
1546}