1use serde::{Deserialize, Serialize};
2use serde::de::{Deserializer, Error};
3
4use crate::types::*;
5use crate::url::*;
6
7#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
9pub enum MessageOrChannelPost {
10 Message(Message),
11 ChannelPost(ChannelPost),
12}
13
14#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
16pub struct Message {
17 pub id: MessageId,
19 pub from: User,
21 pub date: Integer,
23 pub chat: MessageChat,
25 pub forward: Option<Forward>,
27 pub reply_to_message: Option<Box<MessageOrChannelPost>>,
30 pub edit_date: Option<Integer>,
32 pub kind: MessageKind,
34}
35
36#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
38pub struct ChannelPost {
39 pub id: MessageId,
41 pub date: Integer,
43 pub chat: Channel,
45 pub forward: Option<Forward>,
47 pub reply_to_message: Option<Box<MessageOrChannelPost>>,
50 pub edit_date: Option<Integer>,
52 pub kind: MessageKind,
54}
55
56#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
58pub struct Forward {
59 pub date: Integer,
61 pub from: ForwardFrom,
63}
64
65#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
67pub enum ForwardFrom {
68 User {
70 user: User,
72 },
73 Channel {
75 channel: Channel,
77 message_id: Integer,
79 },
80 ChannelHiddenUser {
81 sender_name: String,
82 },
83 HiddenGroupAdmin {
85 chat_id: SupergroupId,
87 title: String,
89 },
90}
91
92#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
94pub enum MessageKind {
95 Text {
97 data: String,
99 entities: Vec<MessageEntity>,
101 },
102 Audio {
104 data: Audio,
106 },
107 Document {
109 data: Document,
111 caption: Option<String>,
113 },
114 Photo {
116 data: Vec<PhotoSize>,
118 caption: Option<String>,
120 media_group_id: Option<String>,
122 },
123 Sticker {
125 data: Sticker,
127 },
128 Video {
130 data: Video,
132 caption: Option<String>,
134 media_group_id: Option<String>,
136 },
137 Voice {
139 data: Voice,
141 },
142 VideoNote {
144 data: VideoNote,
146 },
147 Contact {
149 data: Contact,
151 },
152 Location {
154 data: Location,
156 },
157 Poll {
159 data: Poll,
161 },
162 Venue {
164 data: Venue,
166 },
167 NewChatMembers {
170 data: Vec<User>,
172 },
173 LeftChatMember {
175 data: User,
177 },
178 NewChatTitle {
180 data: String,
182 },
183 NewChatPhoto {
185 data: Vec<PhotoSize>,
187 },
188 DeleteChatPhoto,
190 GroupChatCreated,
192 SupergroupChatCreated,
197 ChannelChatCreated,
202 MigrateToChatId {
204 data: Integer,
206 },
207 MigrateFromChatId {
209 data: Integer,
211 },
212 PinnedMessage {
214 data: Box<MessageOrChannelPost>,
217 },
218 #[doc(hidden)]
219 Unknown { raw: RawMessage },
220}
221
222impl Message {
223 fn from_raw_message(raw: RawMessage) -> Result<Self, String> {
224 let id = raw.message_id;
225 let from = match raw.from.clone() {
226 Some(from) => from,
227 None => return Err(format!("Missing `from` field for Message")),
228 };
229 let date = raw.date;
230 let chat = match raw.chat.clone() {
231 Chat::Private(x) => MessageChat::Private(x),
232 Chat::Group(x) => MessageChat::Group(x),
233 Chat::Supergroup(x) => MessageChat::Supergroup(x),
234 Chat::Unknown(x) => MessageChat::Unknown(x),
235 Chat::Channel(_) => return Err(format!("Channel chat in Message")),
236 };
237
238 let reply_to_message = raw.reply_to_message.clone();
239 let edit_date = raw.edit_date;
240
241 let forward = match (
242 raw.forward_date,
243 &raw.forward_from,
244 &raw.forward_from_chat,
245 raw.forward_from_message_id,
246 &raw.forward_sender_name,
247 ) {
248 (None, &None, &None, None, &None) => None,
249 (Some(date), &Some(ref from), &None, None, &None) => Some(Forward {
250 date: date,
251 from: ForwardFrom::User { user: from.clone() },
252 }),
253 (Some(date), &None, &Some(Chat::Channel(ref channel)), Some(message_id), &None) => {
254 Some(Forward {
255 date: date,
256 from: ForwardFrom::Channel {
257 channel: channel.clone(),
258 message_id: message_id,
259 },
260 })
261 }
262 (Some(date), &None, &None, None, &Some(ref sender_name)) => Some(Forward {
263 date,
264 from: ForwardFrom::ChannelHiddenUser {
265 sender_name: sender_name.clone(),
266 },
267 }),
268 (
269 Some(date),
270 None,
271 Some(Chat::Supergroup(Supergroup {
272 id: chat_id, title, ..
273 })),
274 None,
275 None,
276 ) => Some(Forward {
277 date,
278 from: ForwardFrom::HiddenGroupAdmin {
279 chat_id: chat_id.clone(),
280 title: title.clone(),
281 },
282 }),
283 _ => return Err(format!("invalid forward fields combination")),
284 };
285
286 let make_message = |kind| {
287 Ok(Message {
288 id: id.into(),
289 from: from,
290 date: date,
291 chat: chat,
292 forward: forward,
293 reply_to_message: reply_to_message,
294 edit_date: edit_date,
295 kind: kind,
296 })
297 };
298
299 macro_rules! maybe_field {
300 ($name:ident, $variant:ident) => {{
301 if let Some(val) = raw.$name {
302 return make_message(MessageKind::$variant { data: val });
303 }
304 }};
305 }
306
307 macro_rules! maybe_field_with_caption {
308 ($name:ident, $variant:ident) => {{
309 if let Some(val) = raw.$name {
310 return make_message(MessageKind::$variant {
311 data: val,
312 caption: raw.caption,
313 });
314 }
315 }};
316 }
317
318 macro_rules! maybe_field_with_caption_and_group {
319 ($name:ident, $variant:ident) => {{
320 if let Some(val) = raw.$name {
321 return make_message(MessageKind::$variant {
322 data: val,
323 caption: raw.caption,
324 media_group_id: raw.media_group_id,
325 });
326 }
327 }};
328 }
329
330 macro_rules! maybe_true_field {
331 ($name:ident, $variant:ident) => {{
332 if let Some(True) = raw.$name {
333 return make_message(MessageKind::$variant);
334 }
335 }};
336 }
337
338 if let Some(text) = raw.text {
339 let entities = raw.entities.unwrap_or_else(Vec::new);
340 return make_message(MessageKind::Text {
341 data: text,
342 entities: entities,
343 });
344 }
345
346 maybe_field!(audio, Audio);
347 maybe_field_with_caption!(document, Document);
348 maybe_field_with_caption_and_group!(photo, Photo);
349 maybe_field!(sticker, Sticker);
350 maybe_field_with_caption_and_group!(video, Video);
351 maybe_field!(voice, Voice);
352 maybe_field!(video_note, VideoNote);
353 maybe_field!(contact, Contact);
354 maybe_field!(location, Location);
355 maybe_field!(poll, Poll);
356 maybe_field!(venue, Venue);
357 maybe_field!(new_chat_members, NewChatMembers);
358 maybe_field!(left_chat_member, LeftChatMember);
359 maybe_field!(new_chat_title, NewChatTitle);
360 maybe_field!(new_chat_photo, NewChatPhoto);
361 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
362 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
363 maybe_true_field!(group_chat_created, GroupChatCreated);
364 maybe_true_field!(supergroup_chat_created, SupergroupChatCreated);
365 maybe_true_field!(channel_chat_created, ChannelChatCreated);
366 maybe_field!(migrate_to_chat_id, MigrateToChatId);
367 maybe_field!(migrate_from_chat_id, MigrateFromChatId);
368 maybe_field!(pinned_message, PinnedMessage);
369
370 make_message(MessageKind::Unknown { raw: raw })
371 }
372}
373
374impl<'de> Deserialize<'de> for Message {
375 fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
376 where
377 D: Deserializer<'de>,
378 {
379 let raw: RawMessage = Deserialize::deserialize(deserializer)?;
380
381 Self::from_raw_message(raw).map_err(|err| D::Error::custom(err))
382 }
383}
384
385impl ChannelPost {
386 fn from_raw_message(raw: RawMessage) -> Result<Self, String> {
387 let id = raw.message_id;
388 let date = raw.date;
389 let chat = match raw.chat.clone() {
390 Chat::Channel(channel) => channel,
391 _ => return Err(format!("Expected channel chat type for ChannelMessage")),
392 };
393 let reply_to_message = raw.reply_to_message.clone();
394 let edit_date = raw.edit_date;
395
396 let forward = match (
397 raw.forward_date,
398 &raw.forward_from,
399 &raw.forward_from_chat,
400 raw.forward_from_message_id,
401 &raw.forward_sender_name,
402 ) {
403 (None, &None, &None, None, &None) => None,
404 (Some(date), &Some(ref from), &None, None, &None) => Some(Forward {
405 date: date,
406 from: ForwardFrom::User { user: from.clone() },
407 }),
408 (Some(date), &None, &Some(Chat::Channel(ref channel)), Some(message_id), &None) => {
409 Some(Forward {
410 date: date,
411 from: ForwardFrom::Channel {
412 channel: channel.clone(),
413 message_id: message_id,
414 },
415 })
416 }
417 (Some(date), &None, &None, None, &Some(ref sender_name)) => Some(Forward {
418 date,
419 from: ForwardFrom::ChannelHiddenUser {
420 sender_name: sender_name.clone(),
421 },
422 }),
423 (
424 Some(date),
425 None,
426 Some(Chat::Supergroup(Supergroup {
427 id: chat_id, title, ..
428 })),
429 None,
430 None,
431 ) => Some(Forward {
432 date,
433 from: ForwardFrom::HiddenGroupAdmin {
434 chat_id: chat_id.clone(),
435 title: title.clone(),
436 },
437 }),
438 _ => return Err(format!("invalid forward fields combination")),
439 };
440
441 let make_message = |kind| {
442 Ok(ChannelPost {
443 id: id.into(),
444 date: date,
445 chat: chat,
446 forward: forward,
447 reply_to_message: reply_to_message,
448 edit_date: edit_date,
449 kind: kind,
450 })
451 };
452
453 macro_rules! maybe_field {
454 ($name:ident, $variant:ident) => {{
455 if let Some(val) = raw.$name {
456 return make_message(MessageKind::$variant { data: val });
457 }
458 }};
459 }
460
461 macro_rules! maybe_field_with_caption {
462 ($name:ident, $variant:ident) => {{
463 if let Some(val) = raw.$name {
464 return make_message(MessageKind::$variant {
465 data: val,
466 caption: raw.caption,
467 });
468 }
469 }};
470 }
471
472 macro_rules! maybe_field_with_caption_and_group {
473 ($name:ident, $variant:ident) => {{
474 if let Some(val) = raw.$name {
475 return make_message(MessageKind::$variant {
476 data: val,
477 caption: raw.caption,
478 media_group_id: raw.media_group_id,
479 });
480 }
481 }};
482 }
483
484 macro_rules! maybe_true_field {
485 ($name:ident, $variant:ident) => {{
486 if let Some(True) = raw.$name {
487 return make_message(MessageKind::$variant);
488 }
489 }};
490 }
491
492 if let Some(text) = raw.text {
493 let entities = raw.entities.unwrap_or_else(Vec::new);
494 return make_message(MessageKind::Text {
495 data: text,
496 entities: entities,
497 });
498 }
499
500 maybe_field!(audio, Audio);
501 maybe_field_with_caption!(document, Document);
502 maybe_field_with_caption_and_group!(photo, Photo);
503 maybe_field!(sticker, Sticker);
504 maybe_field_with_caption_and_group!(video, Video);
505 maybe_field!(voice, Voice);
506 maybe_field!(video_note, VideoNote);
507 maybe_field!(contact, Contact);
508 maybe_field!(location, Location);
509 maybe_field!(poll, Poll);
510 maybe_field!(venue, Venue);
511 maybe_field!(new_chat_members, NewChatMembers);
512 maybe_field!(left_chat_member, LeftChatMember);
513 maybe_field!(new_chat_title, NewChatTitle);
514 maybe_field!(new_chat_photo, NewChatPhoto);
515 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
516 maybe_true_field!(delete_chat_photo, DeleteChatPhoto);
517 maybe_true_field!(group_chat_created, GroupChatCreated);
518 maybe_true_field!(supergroup_chat_created, SupergroupChatCreated);
519 maybe_true_field!(channel_chat_created, ChannelChatCreated);
520 maybe_field!(migrate_to_chat_id, MigrateToChatId);
521 maybe_field!(migrate_from_chat_id, MigrateFromChatId);
522 maybe_field!(pinned_message, PinnedMessage);
523
524 make_message(MessageKind::Unknown { raw: raw })
525 }
526}
527
528impl<'de> Deserialize<'de> for ChannelPost {
529 fn deserialize<D>(deserializer: D) -> Result<ChannelPost, D::Error>
531 where
532 D: Deserializer<'de>,
533 {
534 let raw: RawMessage = Deserialize::deserialize(deserializer)?;
535
536 Self::from_raw_message(raw).map_err(|err| D::Error::custom(err))
537 }
538}
539
540impl<'de> Deserialize<'de> for MessageOrChannelPost {
541 fn deserialize<D>(deserializer: D) -> Result<MessageOrChannelPost, D::Error>
543 where
544 D: Deserializer<'de>,
545 {
546 let raw: RawMessage = Deserialize::deserialize(deserializer)?;
547 let is_channel = match raw.chat {
548 Chat::Channel(_) => true,
549 _ => false,
550 };
551
552 let res = if is_channel {
553 ChannelPost::from_raw_message(raw).map(MessageOrChannelPost::ChannelPost)
554 } else {
555 Message::from_raw_message(raw).map(MessageOrChannelPost::Message)
556 };
557
558 res.map_err(|err| D::Error::custom(err))
559 }
560}
561
562#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
564pub struct RawMessage {
565 pub message_id: Integer,
567 pub from: Option<User>,
569 pub date: Integer,
571 pub chat: Chat,
573 pub forward_from: Option<User>,
575 pub forward_from_chat: Option<Chat>,
577 pub forward_from_message_id: Option<Integer>,
579 pub forward_date: Option<Integer>,
581 pub reply_to_message: Option<Box<MessageOrChannelPost>>,
584 pub edit_date: Option<Integer>,
586 pub media_group_id: Option<String>,
588 pub text: Option<String>,
590 pub entities: Option<Vec<MessageEntity>>,
593 pub audio: Option<Audio>,
595 pub document: Option<Document>,
597 pub photo: Option<Vec<PhotoSize>>,
600 pub sticker: Option<Sticker>,
602 pub video: Option<Video>,
604 pub voice: Option<Voice>,
606 pub video_note: Option<VideoNote>,
608 pub caption: Option<String>,
610 pub contact: Option<Contact>,
612 pub location: Option<Location>,
614 pub poll: Option<Poll>,
616 pub venue: Option<Venue>,
618 pub new_chat_members: Option<Vec<User>>,
621 pub left_chat_member: Option<User>,
624 pub new_chat_title: Option<String>,
626 pub new_chat_photo: Option<Vec<PhotoSize>>,
628 pub delete_chat_photo: Option<True>,
630 pub group_chat_created: Option<True>,
632 pub supergroup_chat_created: Option<True>,
637 pub channel_chat_created: Option<True>,
642 pub migrate_to_chat_id: Option<Integer>,
644 pub migrate_from_chat_id: Option<Integer>,
646 pub pinned_message: Option<Box<MessageOrChannelPost>>,
649 pub forward_sender_name: Option<String>,
651}
652
653#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
656pub struct MessageEntity {
657 pub offset: Integer,
659 pub length: Integer,
661 pub kind: MessageEntityKind,
663}
664
665#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
667pub enum MessageEntityKind {
668 Mention,
669 Hashtag,
670 BotCommand,
671 Url,
672 Email,
673 Bold,
674 Italic,
675 Code,
676 Pre,
677 TextLink(String), TextMention(User),
679 #[doc(hidden)]
680 Unknown(RawMessageEntity),
681}
682
683impl<'de> Deserialize<'de> for MessageEntity {
684 fn deserialize<D>(deserializer: D) -> Result<MessageEntity, D::Error>
685 where
686 D: Deserializer<'de>,
687 {
688 use self::MessageEntityKind::*;
689
690 let raw: RawMessageEntity = Deserialize::deserialize(deserializer)?;
691
692 let offset = raw.offset;
693 let length = raw.length;
694
695 macro_rules! required_field {
696 ($name:ident) => {{
697 match raw.$name {
698 Some(val) => val,
699 None => return Err(D::Error::missing_field(stringify!($name))),
700 }
701 }};
702 }
703
704 let kind = match raw.type_.as_str() {
705 "mention" => Mention,
706 "hashtag" => Hashtag,
707 "bot_command" => BotCommand,
708 "url" => Url,
709 "email" => Email,
710 "bold" => Bold,
711 "italic" => Italic,
712 "code" => Code,
713 "pre" => Pre,
714 "text_link" => TextLink(required_field!(url)),
715 "text_mention" => TextMention(required_field!(user)),
716 _ => Unknown(raw),
717 };
718
719 Ok(MessageEntity {
720 offset: offset,
721 length: length,
722 kind: kind,
723 })
724 }
725}
726
727#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
730pub struct RawMessageEntity {
731 #[serde(rename = "type")]
735 pub type_: String,
736 pub offset: Integer,
738 pub length: Integer,
740 pub url: Option<String>,
742 pub user: Option<User>,
744}
745
746#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
748pub struct PhotoSize {
749 pub file_id: String,
751 pub width: Integer,
753 pub height: Integer,
755 pub file_size: Option<Integer>,
757}
758
759#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
761pub struct Audio {
762 pub file_id: String,
764 pub duration: Integer,
766 pub performer: Option<String>,
768 pub title: Option<String>,
770 pub mime_type: Option<String>,
772 pub file_size: Option<Integer>,
774}
775
776#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
778pub struct Document {
779 pub file_id: String,
781 pub thumb: Option<PhotoSize>,
783 pub file_name: Option<String>,
785 pub mime_type: Option<String>,
787 pub file_size: Option<Integer>,
789}
790
791#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
793pub struct Sticker {
794 pub file_id: String,
796 pub file_unique_id: String,
799 pub width: Integer,
801 pub height: Integer,
803 pub thumb: Option<PhotoSize>,
805 pub emoji: Option<String>,
807 pub set_name: Option<String>,
809 pub file_size: Option<Integer>,
811}
812
813#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
815pub struct Video {
816 pub file_id: String,
818 pub width: Integer,
820 pub height: Integer,
822 pub duration: Integer,
824 pub thumb: Option<PhotoSize>,
826 pub mime_type: Option<String>,
828 pub file_size: Option<Integer>,
830}
831
832#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
834pub struct Voice {
835 pub file_id: String,
837 pub duration: Integer,
839 pub mime_type: Option<String>,
841 pub file_size: Option<Integer>,
843}
844
845#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
847pub struct VideoNote {
848 pub file_id: String,
850 pub length: Integer,
851 pub duration: Integer,
853 pub thumb: Option<PhotoSize>,
855 pub file_size: Option<Integer>,
857}
858
859#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
861pub struct Contact {
862 pub phone_number: String,
864 pub first_name: String,
866 pub last_name: Option<String>,
868 pub user_id: Option<Integer>,
870}
871
872#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
874pub struct Location {
875 pub longitude: Float,
877 pub latitude: Float,
879}
880
881#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
883pub struct Venue {
884 pub location: Location,
886 pub title: String,
888 pub address: String,
890 pub foursquare_id: Option<String>,
892}
893
894#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
896pub struct Poll {
897 pub id: String,
899 pub question: String,
901 pub options: Vec<PollOption>,
903 pub total_voter_count: Integer,
905 pub is_closed: bool,
907 pub is_anonymous: bool,
909 #[serde(rename = "type")]
911 pub type_: PollType,
912 pub allows_multiple_answers: bool,
914 pub correct_option_id: Option<Integer>,
917 pub explanation: Option<String>,
919 pub explanation_entities: Option<Vec<MessageEntity>>,
921 pub open_period: Option<Integer>,
923 pub close_date: Option<Integer>,
925}
926
927#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
929pub struct PollAnswer {
930 pub poll_id: String,
932 pub user: User,
934 pub option_ids: Vec<Integer>,
936}
937
938#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
940pub struct PollOption {
941 pub text: String,
943 pub voter_count: Integer,
945}
946
947#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
949pub enum PollType {
950 #[serde(rename = "regular")]
951 Regular,
952 #[serde(rename = "quiz")]
953 Quiz,
954}
955
956#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
958pub struct UserProfilePhotos {
959 pub total_count: Integer,
961 pub photos: Vec<Vec<PhotoSize>>,
963}
964
965#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
969pub struct File {
970 pub file_id: String,
972 pub file_size: Option<Integer>,
974 pub file_path: Option<String>,
976}
977
978impl File {
979 pub fn get_url(&self, token: &str) -> Option<String> {
980 self.file_path
981 .as_ref()
982 .map(|path| format!("{}file/bot{}/{}", telegram_api_url(), token, path))
983 }
984}
985
986#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
989pub enum ParseMode {
990 Markdown,
992 MarkdownV2,
994 #[serde(rename = "HTML")]
996 Html,
997}
998
999impl ::std::fmt::Display for ParseMode {
1000 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
1001 match *self {
1002 ParseMode::Markdown => write!(f, "Markdown"),
1003 ParseMode::MarkdownV2 => write!(f, "MarkdownV2"),
1004 ParseMode::Html => write!(f, "HTML"),
1005 }
1006 }
1007}