1use serde::de::{Deserialize, Deserializer, Error};
2
3use crate::types::*;
4use crate::url::*;
5
6#[derive(Debug, Clone, PartialEq, PartialOrd)]
8pub enum MessageOrChannelPost {
9 Message(Message),
10 ChannelPost(ChannelPost),
11}
12
13#[derive(Debug, Clone, PartialEq, PartialOrd)]
15pub struct Message {
16 pub id: MessageId,
18 pub from: User,
20 pub date: Integer,
22 pub chat: MessageChat,
24 pub forward: Option<Forward>,
26 pub reply_to_message: Option<Box<MessageOrChannelPost>>,
29 pub edit_date: Option<Integer>,
31 pub kind: MessageKind,
33}
34
35#[derive(Debug, Clone, PartialEq, PartialOrd)]
37pub struct ChannelPost {
38 pub id: MessageId,
40 pub date: Integer,
42 pub chat: Channel,
44 pub forward: Option<Forward>,
46 pub reply_to_message: Option<Box<MessageOrChannelPost>>,
49 pub edit_date: Option<Integer>,
51 pub kind: MessageKind,
53}
54
55#[derive(Debug, Clone, PartialEq, PartialOrd)]
57pub struct Forward {
58 pub date: Integer,
60 pub from: ForwardFrom,
62}
63
64#[derive(Debug, Clone, PartialEq, PartialOrd)]
66pub enum ForwardFrom {
67 User {
69 user: User,
71 },
72 Channel {
74 channel: Channel,
76 message_id: Integer,
78 },
79 ChannelHiddenUser {
80 sender_name: String,
81 },
82 HiddenGroupAdmin {
84 chat_id: SupergroupId,
86 title: String,
88 },
89}
90
91#[derive(Debug, Clone, PartialEq, PartialOrd)]
93pub enum MessageKind {
94 Text {
96 data: String,
98 entities: Vec<MessageEntity>,
100 },
101 Audio {
103 data: Audio,
105 },
106 Document {
108 data: Document,
110 caption: Option<String>,
112 },
113 Photo {
115 data: Vec<PhotoSize>,
117 caption: Option<String>,
119 media_group_id: Option<String>,
121 },
122 Sticker {
124 data: Sticker,
126 },
127 Video {
129 data: Video,
131 caption: Option<String>,
133 media_group_id: Option<String>,
135 },
136 Voice {
138 data: Voice,
140 },
141 VideoNote {
143 data: VideoNote,
145 },
146 Contact {
148 data: Contact,
150 },
151 Location {
153 data: Location,
155 },
156 Poll {
158 data: Poll,
160 },
161 Venue {
163 data: Venue,
165 },
166 NewChatMembers {
169 data: Vec<User>,
171 },
172 LeftChatMember {
174 data: User,
176 },
177 NewChatTitle {
179 data: String,
181 },
182 NewChatPhoto {
184 data: Vec<PhotoSize>,
186 },
187 DeleteChatPhoto,
189 GroupChatCreated,
191 SupergroupChatCreated,
196 ChannelChatCreated,
201 MigrateToChatId {
203 data: Integer,
205 },
206 MigrateFromChatId {
208 data: Integer,
210 },
211 PinnedMessage {
213 data: Box<MessageOrChannelPost>,
216 },
217 #[doc(hidden)]
218 Unknown { raw: RawMessage },
219}
220
221impl Message {
222 fn from_raw_message(raw: RawMessage) -> Result<Self, String> {
223 let id = raw.message_id;
224 let from = match raw.from.clone() {
225 Some(from) => from,
226 None => return Err(format!("Missing `from` field for Message")),
227 };
228 let date = raw.date;
229 let chat = match raw.chat.clone() {
230 Chat::Private(x) => MessageChat::Private(x),
231 Chat::Group(x) => MessageChat::Group(x),
232 Chat::Supergroup(x) => MessageChat::Supergroup(x),
233 Chat::Unknown(x) => MessageChat::Unknown(x),
234 Chat::Channel(_) => return Err(format!("Channel chat in Message")),
235 };
236
237 let reply_to_message = raw.reply_to_message.clone();
238 let edit_date = raw.edit_date;
239
240 let forward = match (
241 raw.forward_date,
242 &raw.forward_from,
243 &raw.forward_from_chat,
244 raw.forward_from_message_id,
245 &raw.forward_sender_name,
246 ) {
247 (None, &None, &None, None, &None) => None,
248 (Some(date), &Some(ref from), &None, None, &None) => Some(Forward {
249 date: date,
250 from: ForwardFrom::User { user: from.clone() },
251 }),
252 (Some(date), &None, &Some(Chat::Channel(ref channel)), Some(message_id), &None) => {
253 Some(Forward {
254 date: date,
255 from: ForwardFrom::Channel {
256 channel: channel.clone(),
257 message_id: message_id,
258 },
259 })
260 }
261 (Some(date), &None, &None, None, &Some(ref sender_name)) => Some(Forward {
262 date,
263 from: ForwardFrom::ChannelHiddenUser {
264 sender_name: sender_name.clone(),
265 },
266 }),
267 (
268 Some(date),
269 None,
270 Some(Chat::Supergroup(Supergroup {
271 id: chat_id, title, ..
272 })),
273 None,
274 None,
275 ) => Some(Forward {
276 date,
277 from: ForwardFrom::HiddenGroupAdmin {
278 chat_id: chat_id.clone(),
279 title: title.clone(),
280 },
281 }),
282 _ => return Err(format!("invalid forward fields combination")),
283 };
284
285 let make_message = |kind| {
286 Ok(Message {
287 id: id.into(),
288 from: from,
289 date: date,
290 chat: chat,
291 forward: forward,
292 reply_to_message: reply_to_message,
293 edit_date: edit_date,
294 kind: kind,
295 })
296 };
297
298 macro_rules! maybe_field {
299 ($name:ident, $variant:ident) => {{
300 if let Some(val) = raw.$name {
301 return make_message(MessageKind::$variant { data: val });
302 }
303 }};
304 }
305
306 macro_rules! maybe_field_with_caption {
307 ($name:ident, $variant:ident) => {{
308 if let Some(val) = raw.$name {
309 return make_message(MessageKind::$variant {
310 data: val,
311 caption: raw.caption,
312 });
313 }
314 }};
315 }
316
317 macro_rules! maybe_field_with_caption_and_group {
318 ($name:ident, $variant:ident) => {{
319 if let Some(val) = raw.$name {
320 return make_message(MessageKind::$variant {
321 data: val,
322 caption: raw.caption,
323 media_group_id: raw.media_group_id,
324 });
325 }
326 }};
327 }
328
329 macro_rules! maybe_true_field {
330 ($name:ident, $variant:ident) => {{
331 if let Some(True) = raw.$name {
332 return make_message(MessageKind::$variant);
333 }
334 }};
335 }
336
337 if let Some(text) = raw.text {
338 let entities = raw.entities.unwrap_or_else(Vec::new);
339 return make_message(MessageKind::Text {
340 data: text,
341 entities: entities,
342 });
343 }
344
345 maybe_field!(audio, Audio);
346 maybe_field_with_caption!(document, Document);
347 maybe_field_with_caption_and_group!(photo, Photo);
348 maybe_field!(sticker, Sticker);
349 maybe_field_with_caption_and_group!(video, Video);
350 maybe_field!(voice, Voice);
351 maybe_field!(video_note, VideoNote);
352 maybe_field!(contact, Contact);
353 maybe_field!(location, Location);
354 maybe_field!(poll, Poll);
355 maybe_field!(venue, Venue);
356 maybe_field!(new_chat_members, NewChatMembers);
357 maybe_field!(left_chat_member, LeftChatMember);
358 maybe_field!(new_chat_title, NewChatTitle);
359 maybe_field!(new_chat_photo, NewChatPhoto);
360 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
361 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
362 maybe_true_field!(group_chat_created, GroupChatCreated);
363 maybe_true_field!(supergroup_chat_created, SupergroupChatCreated);
364 maybe_true_field!(channel_chat_created, ChannelChatCreated);
365 maybe_field!(migrate_to_chat_id, MigrateToChatId);
366 maybe_field!(migrate_from_chat_id, MigrateFromChatId);
367 maybe_field!(pinned_message, PinnedMessage);
368
369 make_message(MessageKind::Unknown { raw: raw })
370 }
371}
372
373impl<'de> Deserialize<'de> for Message {
374 fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
375 where
376 D: Deserializer<'de>,
377 {
378 let raw: RawMessage = Deserialize::deserialize(deserializer)?;
379
380 Self::from_raw_message(raw).map_err(|err| D::Error::custom(err))
381 }
382}
383
384impl ChannelPost {
385 fn from_raw_message(raw: RawMessage) -> Result<Self, String> {
386 let id = raw.message_id;
387 let date = raw.date;
388 let chat = match raw.chat.clone() {
389 Chat::Channel(channel) => channel,
390 _ => return Err(format!("Expected channel chat type for ChannelMessage")),
391 };
392 let reply_to_message = raw.reply_to_message.clone();
393 let edit_date = raw.edit_date;
394
395 let forward = match (
396 raw.forward_date,
397 &raw.forward_from,
398 &raw.forward_from_chat,
399 raw.forward_from_message_id,
400 &raw.forward_sender_name,
401 ) {
402 (None, &None, &None, None, &None) => None,
403 (Some(date), &Some(ref from), &None, None, &None) => Some(Forward {
404 date: date,
405 from: ForwardFrom::User { user: from.clone() },
406 }),
407 (Some(date), &None, &Some(Chat::Channel(ref channel)), Some(message_id), &None) => {
408 Some(Forward {
409 date: date,
410 from: ForwardFrom::Channel {
411 channel: channel.clone(),
412 message_id: message_id,
413 },
414 })
415 }
416 (Some(date), &None, &None, None, &Some(ref sender_name)) => Some(Forward {
417 date,
418 from: ForwardFrom::ChannelHiddenUser {
419 sender_name: sender_name.clone(),
420 },
421 }),
422 (
423 Some(date),
424 None,
425 Some(Chat::Supergroup(Supergroup {
426 id: chat_id, title, ..
427 })),
428 None,
429 None,
430 ) => Some(Forward {
431 date,
432 from: ForwardFrom::HiddenGroupAdmin {
433 chat_id: chat_id.clone(),
434 title: title.clone(),
435 },
436 }),
437 _ => return Err(format!("invalid forward fields combination")),
438 };
439
440 let make_message = |kind| {
441 Ok(ChannelPost {
442 id: id.into(),
443 date: date,
444 chat: chat,
445 forward: forward,
446 reply_to_message: reply_to_message,
447 edit_date: edit_date,
448 kind: kind,
449 })
450 };
451
452 macro_rules! maybe_field {
453 ($name:ident, $variant:ident) => {{
454 if let Some(val) = raw.$name {
455 return make_message(MessageKind::$variant { data: val });
456 }
457 }};
458 }
459
460 macro_rules! maybe_field_with_caption {
461 ($name:ident, $variant:ident) => {{
462 if let Some(val) = raw.$name {
463 return make_message(MessageKind::$variant {
464 data: val,
465 caption: raw.caption,
466 });
467 }
468 }};
469 }
470
471 macro_rules! maybe_field_with_caption_and_group {
472 ($name:ident, $variant:ident) => {{
473 if let Some(val) = raw.$name {
474 return make_message(MessageKind::$variant {
475 data: val,
476 caption: raw.caption,
477 media_group_id: raw.media_group_id,
478 });
479 }
480 }};
481 }
482
483 macro_rules! maybe_true_field {
484 ($name:ident, $variant:ident) => {{
485 if let Some(True) = raw.$name {
486 return make_message(MessageKind::$variant);
487 }
488 }};
489 }
490
491 if let Some(text) = raw.text {
492 let entities = raw.entities.unwrap_or_else(Vec::new);
493 return make_message(MessageKind::Text {
494 data: text,
495 entities: entities,
496 });
497 }
498
499 maybe_field!(audio, Audio);
500 maybe_field_with_caption!(document, Document);
501 maybe_field_with_caption_and_group!(photo, Photo);
502 maybe_field!(sticker, Sticker);
503 maybe_field_with_caption_and_group!(video, Video);
504 maybe_field!(voice, Voice);
505 maybe_field!(video_note, VideoNote);
506 maybe_field!(contact, Contact);
507 maybe_field!(location, Location);
508 maybe_field!(poll, Poll);
509 maybe_field!(venue, Venue);
510 maybe_field!(new_chat_members, NewChatMembers);
511 maybe_field!(left_chat_member, LeftChatMember);
512 maybe_field!(new_chat_title, NewChatTitle);
513 maybe_field!(new_chat_photo, NewChatPhoto);
514 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
515 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
516 maybe_true_field!(group_chat_created, GroupChatCreated);
517 maybe_true_field!(supergroup_chat_created, SupergroupChatCreated);
518 maybe_true_field!(channel_chat_created, ChannelChatCreated);
519 maybe_field!(migrate_to_chat_id, MigrateToChatId);
520 maybe_field!(migrate_from_chat_id, MigrateFromChatId);
521 maybe_field!(pinned_message, PinnedMessage);
522
523 make_message(MessageKind::Unknown { raw: raw })
524 }
525}
526
527impl<'de> Deserialize<'de> for ChannelPost {
528 fn deserialize<D>(deserializer: D) -> Result<ChannelPost, D::Error>
530 where
531 D: Deserializer<'de>,
532 {
533 let raw: RawMessage = Deserialize::deserialize(deserializer)?;
534
535 Self::from_raw_message(raw).map_err(|err| D::Error::custom(err))
536 }
537}
538
539impl<'de> Deserialize<'de> for MessageOrChannelPost {
540 fn deserialize<D>(deserializer: D) -> Result<MessageOrChannelPost, D::Error>
542 where
543 D: Deserializer<'de>,
544 {
545 let raw: RawMessage = Deserialize::deserialize(deserializer)?;
546 let is_channel = match raw.chat {
547 Chat::Channel(_) => true,
548 _ => false,
549 };
550
551 let res = if is_channel {
552 ChannelPost::from_raw_message(raw).map(MessageOrChannelPost::ChannelPost)
553 } else {
554 Message::from_raw_message(raw).map(MessageOrChannelPost::Message)
555 };
556
557 res.map_err(|err| D::Error::custom(err))
558 }
559}
560
561#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
563pub struct RawMessage {
564 pub message_id: Integer,
566 pub from: Option<User>,
568 pub date: Integer,
570 pub chat: Chat,
572 pub forward_from: Option<User>,
574 pub forward_from_chat: Option<Chat>,
576 pub forward_from_message_id: Option<Integer>,
578 pub forward_date: Option<Integer>,
580 pub reply_to_message: Option<Box<MessageOrChannelPost>>,
583 pub edit_date: Option<Integer>,
585 pub media_group_id: Option<String>,
587 pub text: Option<String>,
589 pub entities: Option<Vec<MessageEntity>>,
592 pub audio: Option<Audio>,
594 pub document: Option<Document>,
596 pub photo: Option<Vec<PhotoSize>>,
599 pub sticker: Option<Sticker>,
601 pub video: Option<Video>,
603 pub voice: Option<Voice>,
605 pub video_note: Option<VideoNote>,
607 pub caption: Option<String>,
609 pub contact: Option<Contact>,
611 pub location: Option<Location>,
613 pub poll: Option<Poll>,
615 pub venue: Option<Venue>,
617 pub new_chat_members: Option<Vec<User>>,
620 pub left_chat_member: Option<User>,
623 pub new_chat_title: Option<String>,
625 pub new_chat_photo: Option<Vec<PhotoSize>>,
627 pub delete_chat_photo: Option<True>,
629 pub group_chat_created: Option<True>,
631 pub supergroup_chat_created: Option<True>,
636 pub channel_chat_created: Option<True>,
641 pub migrate_to_chat_id: Option<Integer>,
643 pub migrate_from_chat_id: Option<Integer>,
645 pub pinned_message: Option<Box<MessageOrChannelPost>>,
648 pub forward_sender_name: Option<String>,
650}
651
652#[derive(Debug, Clone, PartialEq, PartialOrd)]
655pub struct MessageEntity {
656 pub offset: Integer,
658 pub length: Integer,
660 pub kind: MessageEntityKind,
662}
663
664#[derive(Debug, Clone, PartialEq, PartialOrd)]
666pub enum MessageEntityKind {
667 Mention,
668 Hashtag,
669 BotCommand,
670 Url,
671 Email,
672 Bold,
673 Italic,
674 Code,
675 Pre,
676 TextLink(String), TextMention(User),
678 #[doc(hidden)]
679 Unknown(RawMessageEntity),
680}
681
682impl<'de> Deserialize<'de> for MessageEntity {
683 fn deserialize<D>(deserializer: D) -> Result<MessageEntity, D::Error>
684 where
685 D: Deserializer<'de>,
686 {
687 use self::MessageEntityKind::*;
688
689 let raw: RawMessageEntity = Deserialize::deserialize(deserializer)?;
690
691 let offset = raw.offset;
692 let length = raw.length;
693
694 macro_rules! required_field {
695 ($name:ident) => {{
696 match raw.$name {
697 Some(val) => val,
698 None => return Err(D::Error::missing_field(stringify!($name))),
699 }
700 }};
701 }
702
703 let kind = match raw.type_.as_str() {
704 "mention" => Mention,
705 "hashtag" => Hashtag,
706 "bot_command" => BotCommand,
707 "url" => Url,
708 "email" => Email,
709 "bold" => Bold,
710 "italic" => Italic,
711 "code" => Code,
712 "pre" => Pre,
713 "text_link" => TextLink(required_field!(url)),
714 "text_mention" => TextMention(required_field!(user)),
715 _ => Unknown(raw),
716 };
717
718 Ok(MessageEntity {
719 offset: offset,
720 length: length,
721 kind: kind,
722 })
723 }
724}
725
726#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
729pub struct RawMessageEntity {
730 #[serde(rename = "type")]
734 pub type_: String,
735 pub offset: Integer,
737 pub length: Integer,
739 pub url: Option<String>,
741 pub user: Option<User>,
743}
744
745#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
747pub struct PhotoSize {
748 pub file_id: String,
750 pub width: Integer,
752 pub height: Integer,
754 pub file_size: Option<Integer>,
756}
757
758#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
760pub struct Audio {
761 pub file_id: String,
763 pub duration: Integer,
765 pub performer: Option<String>,
767 pub title: Option<String>,
769 pub mime_type: Option<String>,
771 pub file_size: Option<Integer>,
773}
774
775#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
777pub struct Document {
778 pub file_id: String,
780 pub file_unique_id: Option<String>,
782 pub thumb: Option<PhotoSize>,
784 pub file_name: Option<String>,
786 pub mime_type: Option<String>,
788 pub file_size: Option<Integer>,
790 pub file_path: Option<String>,
792}
793
794#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
796pub struct Sticker {
797 pub file_id: String,
799 pub file_unique_id: String,
802 pub width: Integer,
804 pub height: Integer,
806 pub thumb: Option<PhotoSize>,
808 pub emoji: Option<String>,
810 pub set_name: Option<String>,
812 pub file_size: Option<Integer>,
814}
815
816#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
818pub struct Video {
819 pub file_id: String,
821 pub width: Integer,
823 pub height: Integer,
825 pub duration: Integer,
827 pub thumb: Option<PhotoSize>,
829 pub mime_type: Option<String>,
831 pub file_size: Option<Integer>,
833}
834
835#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
837pub struct Voice {
838 pub file_id: String,
840 pub duration: Integer,
842 pub mime_type: Option<String>,
844 pub file_size: Option<Integer>,
846}
847
848#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
850pub struct VideoNote {
851 pub file_id: String,
853 pub length: Integer,
854 pub duration: Integer,
856 pub thumb: Option<PhotoSize>,
858 pub file_size: Option<Integer>,
860}
861
862#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
864pub struct Contact {
865 pub phone_number: String,
867 pub first_name: String,
869 pub last_name: Option<String>,
871 pub user_id: Option<Integer>,
873}
874
875#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
877pub struct Location {
878 pub longitude: Float,
880 pub latitude: Float,
882}
883
884#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
886pub struct Venue {
887 pub location: Location,
889 pub title: String,
891 pub address: String,
893 pub foursquare_id: Option<String>,
895}
896
897#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
899pub struct Poll {
900 pub id: String,
902 pub question: String,
904 pub options: Vec<PollOption>,
906 pub total_voter_count: Integer,
908 pub is_closed: bool,
910 pub is_anonymous: bool,
912 #[serde(rename = "type")]
914 pub type_: PollType,
915 pub allows_multiple_answers: bool,
917 pub correct_option_id: Option<Integer>,
920 pub explanation: Option<String>,
922 pub explanation_entities: Option<Vec<MessageEntity>>,
924 pub open_period: Option<Integer>,
926 pub close_date: Option<Integer>,
928}
929
930#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
932pub struct PollAnswer {
933 pub poll_id: String,
935 pub user: User,
937 pub option_ids: Vec<Integer>,
939}
940
941#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
943pub struct PollOption {
944 pub text: String,
946 pub voter_count: Integer,
948}
949
950#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
952pub enum PollType {
953 #[serde(rename = "regular")]
954 Regular,
955 #[serde(rename = "quiz")]
956 Quiz,
957}
958
959#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
961pub struct UserProfilePhotos {
962 pub total_count: Integer,
964 pub photos: Vec<Vec<PhotoSize>>,
966}
967
968#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
972pub struct File {
973 pub file_id: String,
975 pub file_size: Option<Integer>,
977 pub file_path: Option<String>,
979}
980
981impl File {
982 pub fn get_url(&self, token: &str) -> Option<String> {
983 self.file_path
984 .as_ref()
985 .map(|path| format!("{}file/bot{}/{}", telegram_api_url(), token, path))
986 }
987}
988
989#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize)]
992pub enum ParseMode {
993 Markdown,
995 MarkdownV2,
997 #[serde(rename = "HTML")]
999 Html,
1000}
1001
1002impl ::std::fmt::Display for ParseMode {
1003 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1004 match *self {
1005 ParseMode::Markdown => write!(f, "Markdown"),
1006 ParseMode::MarkdownV2 => write!(f, "MarkdownV2"),
1007 ParseMode::Html => write!(f, "HTML"),
1008 }
1009 }
1010}