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