1 module telega.botapi;
2 
3 import vibe.http.client : HTTPMethod;
4 import vibe.core.core;
5 import vibe.core.log;
6 import asdf;
7 import std.conv;
8 import std.typecons;
9 import std.exception;
10 import std.traits;
11 import telega.http;
12 import telega.serialization;
13 
14 class TelegramBotApiException : Exception
15 {
16     ushort code;
17 
18     this(ushort code, string description, string file = __FILE__, size_t line = __LINE__,
19          Throwable next = null) @nogc @safe pure nothrow
20     {
21         this.code = code;
22         super(description, file, line, next);
23     }
24 }
25 
26 enum isTelegramId(T) = isSomeString!T || isIntegral!T;
27 
28 /******************************************************************/
29 /*                    Telegram types and enums                    */
30 /******************************************************************/
31 
32 struct User
33 {
34     int    id;
35     bool   is_bot;
36     string first_name;
37 
38     Nullable!string last_name;
39     Nullable!string username;
40     Nullable!string language_code;
41 }
42 
43 unittest
44 {
45     string json = `{
46         "id": 42,
47         "is_bot": false,
48         "first_name": "FirstName"
49     }`;
50 
51     User u = deserialize!User(json);
52 
53     assert(u.last_name.isNull);
54 }
55 
56 unittest
57 {
58     string json = `{
59         "id": 42,
60         "is_bot": false,
61         "first_name": "FirstName",
62         "last_name": "LastName"
63     }`;
64 
65     User u = deserialize!User(json);
66 
67     assert(false == u.last_name.isNull);
68 }
69 
70 
71 
72 @serializedAs!ChatTypeProxy
73 enum ChatType : string
74 {
75     Private    = "private",
76     Group      = "group",
77     Supergroup = "supergroup",
78     Channel    = "channel"
79 }
80 
81 struct ChatTypeProxy
82 {
83     ChatType t;
84 
85     this(ChatType type)
86     {
87         t = type;
88     }
89 
90     ChatType opCast(T : ChatType)()
91     {
92         return t;
93     }
94 
95     static ChatTypeProxy deserialize(Asdf v)
96     {
97         return ChatTypeProxy(cast(ChatType)cast(string)v);
98     }
99 }
100 
101 struct Chat
102 {
103     long id;
104     ChatType type;
105     Nullable!string title;
106     Nullable!string first_name;
107     Nullable!string last_name;
108     Nullable!string username;
109     Nullable!bool all_members_are_administrators;
110     Nullable!ChatPhoto photo;
111     Nullable!string description;
112     Nullable!string invite_link;
113     // TODO Nullable!Message pinned_message;
114     Nullable!string sticker_set_name;
115     Nullable!bool can_set_sticker_set;
116 }
117 
118 unittest
119 {
120     string json = `{
121         "id": 42,
122         "type": "group",
123         "title": "chat title"
124     }`;
125 
126     Chat c = deserialize!Chat(json);
127 
128     assert(c.id == 42);
129     assert(c.type == ChatType.Group);
130 }
131 
132 struct Message
133 {
134     uint                 message_id;
135     uint                 date;
136     Chat                 chat;
137     Nullable!User        from;
138     Nullable!User        forward_from;
139     Nullable!Chat        forward_from_chat;
140     Nullable!uint        forward_from_message_id;
141     Nullable!string      forward_signature;
142     Nullable!uint        forward_date;
143     Nullable!uint        edit_date;
144     Nullable!string      media_group_id;
145     Nullable!string      author_signature;
146     Nullable!string      text;
147     Nullable!MessageEntity[] entities;
148     Nullable!MessageEntity[] caption_entities;
149     Nullable!Audio           audio;
150     Nullable!Document        document;
151     Nullable!Animation       animation;
152     Nullable!Game            game;
153     Nullable!PhotoSize[]     photo;
154     Nullable!Sticker         sticker;
155     Nullable!Video           video;
156     Nullable!Voice           voice;
157     Nullable!VideoNote       video_note;
158     // TODO Nullable!Message reply_to_message;
159     // TODO Nullable!Message pinned_message;
160     Nullable!string          caption;
161     Nullable!Contact         contact;
162     Nullable!Location        location;
163     Nullable!Venue           venue;
164     Nullable!User[]          new_chat_members;
165     Nullable!User            left_chat_member;
166     Nullable!string          new_chat_title;
167     Nullable!PhotoSize[]     new_chat_photo;
168     Nullable!bool            delete_chat_photo;
169     Nullable!bool            group_chat_created;
170     Nullable!bool            supergroup_chat_created;
171     Nullable!bool            channel_chat_created;
172     Nullable!long            migrate_to_chat_id;
173     Nullable!long            migrate_from_chat_id;
174     Nullable!Invoice         invoice;
175     Nullable!SuccessfulPayment successful_payment;
176     Nullable!string              connected_website;
177 
178     @property
179     uint id()
180     {
181         return message_id;
182     }
183 }
184 
185 struct Update
186 {
187     uint             update_id;
188     Nullable!Message message;
189 
190     Nullable!Message edited_message;
191     Nullable!Message channel_post;
192     Nullable!Message edited_channel_post;
193     Nullable!InlineQuery        inline_query;
194     Nullable!ChosenInlineResult chosen_inline_result;
195     Nullable!CallbackQuery      callback_query;
196     Nullable!ShippingQuery      shipping_query;
197     Nullable!PreCheckoutQuery   pre_checkout_query;
198 
199     @property
200     uint id()
201     {
202         return update_id;
203     }
204 }
205 
206 unittest
207 {
208     string json = `{
209         "update_id": 143,
210         "message": {
211             "message_id": 243,
212             "text": "message text"
213         }
214     }`;
215 
216     Update u = deserialize!Update(json);
217 
218     assert(u.id == 143);
219     assert(u.message.message_id == 243);
220     assert(u.message.text == "message text");
221 }
222 
223 struct WebhookInfo
224 {
225     string   url;
226     bool     has_custom_certificate;
227     uint     pending_update_count;
228     Nullable!uint     last_error_date;
229     Nullable!string   last_error_message;
230     Nullable!uint     max_connections;
231     Nullable!string[] allowed_updates;
232 }
233 
234 enum ParseMode
235 {
236     Markdown = "Markdown",
237     HTML     = "HTML",
238     None     = "",
239 }
240 
241 struct MessageEntity
242 {
243     string        type;
244     uint          offset;
245     uint          length;
246     Nullable!string  url;
247     Nullable!User    user;
248 }
249 
250 struct PhotoSize
251 {
252     string        file_id;
253     int           width;
254     int           height;
255 
256     Nullable!uint file_size;
257 }
258 
259 struct Audio
260 {
261     string file_id;
262     uint   duration;
263     Nullable!string performer;
264     Nullable!string title;
265     Nullable!string mime_type;
266     Nullable!uint   file_size;
267     Nullable!PhotoSize thumb;
268 }
269 
270 // TODO Add Nullable fields
271 struct Document
272 {
273     string    file_id;
274     PhotoSize thumb;
275     string    file_name;
276     string    mime_type;
277     uint      file_size;
278 }
279 
280 // TODO Add Nullable fields
281 struct Video
282 {
283     string file_id;
284     uint width;
285     uint height;
286     uint duration;
287     PhotoSize thumb;
288     string mime_type;
289     uint file_size;
290 }
291 
292 // TODO Add Nullable fields
293 struct Voice
294 {
295     string file_id;
296     uint   duration;
297     string mime_type;
298     uint   file_size;
299 }
300 
301 // TODO Add Nullable fields
302 struct VideoNote
303 {
304     string    file_id;
305     uint      length;
306     uint      duration;
307     PhotoSize thumb;
308     uint      file_size;
309 }
310 
311 // TODO Add Nullable fields
312 struct Contact
313 {
314     string phone_number;
315     string first_name;
316     string last_name;
317     string user_id;
318 }
319 
320 // TODO Add Nullable fields
321 struct Location
322 {
323     float longitude;
324     float latitude;
325 }
326 
327 // TODO Add Nullable fields
328 struct Venue
329 {
330     Location location;
331     string   title;
332     string   address;
333     string   foursquare_id;
334 }
335 
336 // TODO Add Nullable fields
337 struct UserProfilePhotos
338 {
339     uint          total_count;
340     PhotoSize[][] photos;
341 }
342 
343 // TODO Add Nullable fields
344 struct File
345 {
346     string file_id;
347     uint   file_size;
348     string file_path;
349 }
350 
351 import std.meta : AliasSeq, staticIndexOf;
352 import std.variant : Algebraic;
353 
354 alias ReplyMarkupStructs = AliasSeq!(ReplyKeyboardMarkup, ReplyKeyboardRemove, InlineKeyboardMarkup, ForceReply);
355 
356 /**
357  Abstract structure for unioining ReplyKeyboardMarkup, ReplyKeyboardRemove,
358  InlineKeyboardMarkup and ForceReply
359 */
360 
361 alias ReplyMarkup = JsonableAlgebraicProxy!ReplyMarkupStructs;
362 enum isReplyMarkup(T) =
363     is(T == ReplyMarkup) || staticIndexOf!(T, ReplyMarkupStructs) >= 0;
364 
365 import std.algorithm.iteration;
366 import std.array;
367 
368 static bool falseIfNull(Nullable!bool value)
369 {
370     if (value.isNull) {
371         return false;
372     }
373 
374     return cast(bool)value;
375 }
376 
377 static bool trueIfNull(Nullable!bool value)
378 {
379     if (value.isNull) {
380         return true;
381     }
382 
383     return cast(bool)value;
384 }
385 
386 struct ReplyKeyboardMarkup
387 {
388     KeyboardButton[][] keyboard;
389 
390  // TODO   @serializationTransformOut!falseIfNull
391     Nullable!bool      resize_keyboard = false;
392 
393 // TODO     @serializationTransformOut!falseIfNull
394     Nullable!bool      one_time_keyboard = false;
395 
396 // TODO    @serializationTransformOut!falseIfNull
397     Nullable!bool      selective = false;
398 
399     this (string[][] keyboard)
400     {
401         this.keyboard = keyboard.map!toKeyboardButtonRow.array;
402     }
403 
404     void opOpAssign(string op : "~")(KeyboardButton[] buttons)
405     {
406         keyboard ~= buttons;
407     }
408 }
409 
410 struct KeyboardButton
411 {
412     string text;
413 
414     Nullable!bool   request_contact;
415     Nullable!bool   request_location;
416 
417     this(string text, bool requestContact = false, bool requestLocation = false)
418     {
419         this.text = text;
420         this.request_contact = requestContact;
421         this.request_location = requestLocation;
422     }
423 }
424 
425 KeyboardButton[] toKeyboardButtonRow(string[] row)
426 {
427     return row.map!(b => KeyboardButton(b)).array;
428 }
429 
430 struct ReplyKeyboardRemove
431 {
432     bool remove_keyboard = true;
433     Nullable!bool           selective = false;
434 }
435 
436 struct InlineKeyboardMarkup
437 {
438     InlineKeyboardButton[][] inline_keyboard;
439 }
440 
441 struct InlineKeyboardButton
442 {
443     string       text;
444     Nullable!string       url;
445     Nullable!string       callback_data;
446     Nullable!string       switch_inline_query;
447     Nullable!string       switch_inline_query_current_chat;
448     Nullable!CallbackGame callback_game;
449     Nullable!bool         pay;
450 }
451 
452 // TODO Add Nullable fields
453 struct CallbackQuery
454 {
455     string           id;
456     User             from;
457     Nullable!Message message;
458     string           inline_message_id;
459     string           chat_instance;
460     string           data;
461     string           game_short_name;
462 }
463 
464 struct ForceReply
465 {
466     bool     force_reply = true;
467     Nullable!bool     selective;
468 }
469 
470 struct ChatPhoto
471 {
472     string small_file_id;
473     string big_file_id;
474 }
475 
476 // TODO Add Nullable fields
477 struct ChatMember
478 {
479     User   user;
480     string status;
481     uint   until_date;
482     bool   can_be_edited;
483     bool   can_change_info;
484     bool   can_post_messages;
485     bool   can_edit_messages;
486     bool   can_delete_messages;
487     bool   can_invite_users;
488     bool   can_restrict_members;
489     bool   can_pin_messages;
490     bool   can_promote_members;
491     bool   can_send_messages;
492     bool   can_send_media_messages;
493     bool   can_send_other_messages;
494     bool   can_add_web_page_previews;
495 }
496 
497 // TODO Add Nullable fields
498 struct ResponseParameters
499 {
500     long migrate_to_chat_id;
501     uint retry_after;
502 }
503 
504 alias InputMediaStructs = AliasSeq!(InputMediaPhoto, InputMediaVideo);
505 
506 alias InputMedia = JsonableAlgebraicProxy!InputMediaStructs;
507 
508 struct InputMediaPhoto
509 {
510     string type;
511     string media;
512     Nullable!string caption;
513     Nullable!ParseMode parse_mode;
514 }
515 
516 struct InputMediaVideo
517 {
518     string type;
519     string media;
520     Nullable!string    caption;
521     Nullable!ParseMode parse_mode;
522     Nullable!uint   width;
523     Nullable!uint   height;
524     Nullable!uint   duration;
525     Nullable!bool   supports_streaming;
526 }
527 
528 // TODO InputMediaAnimation
529 // TODO InputMediaAudio
530 // TODO InputMediaDocument
531 
532 struct InputFile
533 {
534     // no fields
535 }
536 
537 struct Sticker
538 {
539     string       file_id;
540     uint         width;
541     uint         height;
542     PhotoSize    thumb;
543     string       emoji;
544     string       set_name;
545     MaskPosition mask_position;
546     uint         file_size;
547 }
548 
549 struct StickerSet
550 {
551     string    name;
552     string    title;
553     bool      contains_masks;
554     Sticker[] stickers;
555 }
556 
557 struct MaskPosition
558 {
559     string point;
560     float  x_shift;
561     float  y_shift;
562     float  scale;
563 }
564 
565 
566 /*** Inline mode types ***/
567 
568 struct InlineQuery
569 {
570     string id;
571     User from;
572     Nullable!Location location;
573     string query;
574     string offset;
575 }
576 
577 alias InlineQueryResultStructs = AliasSeq!(
578     InlineQueryResultArticle, InlineQueryResultPhoto, InlineQueryResultGif, InlineQueryResultMpeg4Gif,
579     InlineQueryResultVideo, InlineQueryResultAudio, InlineQueryResultVoice, InlineQueryResultDocument,
580     InlineQueryResultLocation, InlineQueryResultVenue, InlineQueryResultContact, InlineQueryResultGame,
581     InlineQueryResultCachedPhoto, InlineQueryResultCachedGif, InlineQueryResultCachedMpeg4Gif,
582     InlineQueryResultCachedSticker, InlineQueryResultCachedDocument, InlineQueryResultCachedVideo,
583     InlineQueryResultCachedVoice, InlineQueryResultCachedAudio
584 );
585 
586 alias InlineQueryResult = JsonableAlgebraicProxy!InlineQueryResultStructs;
587 
588 mixin template InlineQueryFields()
589 {
590     Nullable!InlineKeyboardMarkup reply_markup;
591     Nullable!InputMessageContent  input_message_content;
592 }
593 
594 struct InlineQueryResultArticle
595 {
596     string type = "article";
597     string id;
598     string title;
599     Nullable!string url;
600     Nullable!bool hide_url;
601     Nullable!string description;
602     Nullable!string thumb_url;
603     Nullable!uint thumb_width;
604     Nullable!uint thumb_height;
605 
606     Nullable!InlineKeyboardMarkup reply_markup;
607     InputMessageContent  input_message_content; // can't be nullable
608 }
609 
610 struct InlineQueryResultPhoto
611 {
612     string type = "photo";
613     string id;
614     string photo_url;
615     string thumb_url;
616     Nullable!uint photo_width;
617     Nullable!uint photo_height;
618     Nullable!string title;
619     Nullable!string description;
620     Nullable!string caption;
621     Nullable!ParseMode parse_mode;
622 
623     mixin InlineQueryFields;
624 }
625 
626 struct InlineQueryResultGif
627 {
628     string type = "gif";
629     string id;
630     string gif_url;
631     Nullable!uint gif_width;
632     Nullable!uint gif_height;
633     Nullable!uint gif_duration;
634     Nullable!string thumb_url;
635     Nullable!string title;
636     Nullable!string caption;
637     Nullable!ParseMode parse_mode;
638 
639     mixin InlineQueryFields;
640 }
641 
642 struct InlineQueryResultMpeg4Gif
643 {
644     string type ="mpeg4_gif";
645     string id;
646     string mpeg4_url;
647     Nullable!uint mpeg4_width;
648     Nullable!uint mpeg4_height;
649     Nullable!uint mpeg4_duration;
650     Nullable!string thumb_url;
651     Nullable!string title;
652     Nullable!string caption;
653     Nullable!ParseMode parse_mode;
654 
655     mixin InlineQueryFields;
656 }
657 
658 struct InlineQueryResultVideo
659 {
660     string type ="video";
661     string id;
662     string video_url;
663     string mime_type;
664     string thumb_url;
665     string title;
666     Nullable!string caption;
667     Nullable!ParseMode parse_mode;
668     Nullable!uint video_width;
669     Nullable!uint video_height;
670     Nullable!uint video_duration;
671     Nullable!string description;
672 
673     mixin InlineQueryFields;
674 }
675 
676 struct InlineQueryResultAudio
677 {
678     string    type = "audio";
679     string    id;
680     string    audio_url;
681     string    title;
682     Nullable!string    caption;
683     Nullable!ParseMode parse_mode;
684     Nullable!string    performer;
685     Nullable!uint      audio_duration;
686 
687     mixin InlineQueryFields;
688 }
689 
690 struct InlineQueryResultVoice
691 {
692     string    type = "voice";
693     string    id;
694     string    voice_url;
695     string    title;
696     Nullable!string    caption;
697     Nullable!ParseMode parse_mode;
698     Nullable!uint      voice_duration;
699 
700     mixin InlineQueryFields;
701 }
702 
703 struct InlineQueryResultDocument
704 {
705     string    type = "document";
706     string    id;
707     string    title;
708     Nullable!string    caption;
709     Nullable!ParseMode parse_mode;
710     Nullable!string    document_url;
711     Nullable!string    mime_type;
712     Nullable!string    description;
713     Nullable!string    thumb_url;
714     Nullable!uint      thumb_width;
715     Nullable!uint      thumb_height;
716 
717     mixin InlineQueryFields;
718 }
719 
720 struct InlineQueryResultLocation
721 {
722     string type = "location";
723     string id;
724     float latitude;
725     float longitude;
726     string title;
727     Nullable!uint live_period;
728     Nullable!string thumb_url;
729     Nullable!uint thumb_width;
730     Nullable!uint thumb_height;
731 
732     mixin InlineQueryFields;
733 }
734 
735 struct InlineQueryResultVenue
736 {
737     string type = "venue";
738     string id;
739     float latitude;
740     float longitude;
741     string title;
742     string address;
743     Nullable!string foursquare_id;
744     Nullable!string thumb_url;
745     Nullable!uint thumb_width;
746     Nullable!uint thumb_height;
747 
748     mixin InlineQueryFields;
749 }
750 
751 struct InlineQueryResultContact
752 {
753     string type = "contact";
754     string id;
755     string phone_number;
756     string first_name;
757     Nullable!string last_name;
758     Nullable!string thumb_url;
759     Nullable!uint thumb_width;
760     Nullable!uint thumb_height;
761 
762     mixin InlineQueryFields;
763 }
764 
765 struct InlineQueryResultGame
766 {
767     string type = "game";
768     string id;
769     string game_short_name;
770     Nullable!InlineKeyboardMarkup reply_markup;
771 }
772 
773 
774 struct InlineQueryResultCachedPhoto
775 {
776     string type = "photo";
777     string id;
778     string photo_file_id;
779     Nullable!string title;
780     Nullable!string description;
781     Nullable!string caption;
782     Nullable!ParseMode parse_mode;
783 
784     mixin InlineQueryFields;
785 }
786 
787 struct InlineQueryResultCachedGif
788 {
789     string type = "gif";
790     string id;
791     string gif_file_id;
792     Nullable!string title;
793     Nullable!string caption;
794     Nullable!ParseMode parse_mode;
795 
796     mixin InlineQueryFields;
797 }
798 
799 struct InlineQueryResultCachedMpeg4Gif
800 {
801     string type = "mpeg4_gif";
802     string id;
803     string mpeg4_file_id;
804     Nullable!string title;
805     Nullable!string caption;
806     Nullable!ParseMode parse_mode;
807 
808     mixin InlineQueryFields;
809 }
810 
811 struct InlineQueryResultCachedSticker
812 {
813     string type = "sticker";
814     string id;
815     string sticker_file_id;
816 
817     mixin InlineQueryFields;
818 }
819 
820 struct InlineQueryResultCachedDocument
821 {
822     string type = "document";
823     string    id;
824     string    title;
825     string    document_file_id;
826     Nullable!string    description;
827     Nullable!string    caption;
828     Nullable!ParseMode parse_mode;
829 
830     mixin InlineQueryFields;
831 }
832 
833 struct InlineQueryResultCachedVideo
834 {
835     string type = "video";
836     string    id;
837     string    video_file_id;
838     string    title;
839     Nullable!string    description;
840     Nullable!string    caption;
841     Nullable!ParseMode parse_mode;
842 
843     mixin InlineQueryFields;
844 }
845 
846 struct InlineQueryResultCachedVoice
847 {
848     string type = "voice";
849     string    id;
850     string    voice_file_id;
851     string    title;
852     Nullable!string    caption;
853     Nullable!ParseMode parse_mode;
854 
855     mixin InlineQueryFields;
856 }
857 
858 
859 struct InlineQueryResultCachedAudio
860 {
861     string type = "audio";
862     string    id;
863     string    audio_file_id;
864     Nullable!string    caption;
865     Nullable!ParseMode parse_mode;
866 
867     mixin InlineQueryFields;
868 }
869 
870 alias InputMessageContentStructs = AliasSeq!(
871     InputTextMessageContent, InputLocationMessageContent, InputVenueMessageContent, InputContactMessageContent
872 );
873 
874 alias InputMessageContent = JsonableAlgebraicProxy!InputMessageContentStructs;
875 
876 struct InputTextMessageContent
877 {
878     string message_text;
879     Nullable!ParseMode parse_mode;
880     Nullable!bool   disable_web_page_preview;
881 }
882 
883 struct InputLocationMessageContent
884 {
885     float latitude;
886     float longitude;
887     Nullable!uint  live_period;
888 }
889 
890 struct InputVenueMessageContent
891 {
892     float  latitude;
893     float  longitude;
894     string title;
895     string address;
896     Nullable!string foursquare_id;
897     // TODO new field Nullable!string foursquare_type;
898 }
899 
900 struct InputContactMessageContent
901 {
902     string phone_number;
903     string first_name;
904     Nullable!string last_name;
905     // TODO new field Nullable!string vcard;
906 }
907 
908 struct ChosenInlineResult
909 {
910     string   result_id;
911     User     from;
912     Nullable!Location location;
913     Nullable!string   inline_message_id;
914     string   query;
915 }
916 
917 /*** Payments types ***/
918 struct LabeledPrice
919 {
920     string label;
921     uint   amount;
922 }
923 
924 struct Invoice
925 {
926     string title;
927     string description;
928     string start_parameter;
929     string currency;
930     uint   total_amount;
931 }
932 
933 struct ShippingAddress
934 {
935     string country_code;
936     string state;
937     string city;
938     string street_line1;
939     string street_line2;
940     string post_code;
941 }
942 
943 // TODO add nullable fields
944 struct OrderInfo
945 {
946     string name;
947     string phone_number;
948     string email;
949     Nullable!ShippingAddress shipping_address;
950 }
951 
952 struct ShippingOption
953 {
954     string id;
955     string title;
956     LabeledPrice[] prices;
957 }
958 
959 // TODO add nullable fields
960 struct SuccessfulPayment
961 {
962     string currency;
963     uint   total_amount;
964     string invoice_payload;
965     string shipping_option_id;
966     Nullable!OrderInfo order_info;
967     string telegram_payment_charge_id;
968     string provider_payment_charge_id;
969 }
970 
971 struct ShippingQuery
972 {
973     string id;
974     User   from;
975     string invoice_payload;
976     ShippingAddress shipping_address;
977 }
978 
979 // TODO add nullable fields
980 struct PreCheckoutQuery
981 {
982     string             id;
983     User               from;
984     string             currency;
985     uint               total_amount;
986     string             invoice_payload;
987     string             shipping_option_id;
988     Nullable!OrderInfo order_info;
989 }
990 
991 /*** Telegram Passport ***/
992 // TODO
993 
994 /*** Games types ***/
995 
996 // TODO add nullable fields
997 struct Game
998 {
999     string        title;
1000     string        description;
1001     PhotoSize[]   photo;
1002     string        text;
1003     MessageEntity text_entities;
1004     Animation     animation;
1005 }
1006 
1007 // TODO add nullable fields and a new fields
1008 struct Animation
1009 {
1010     string    file_id;
1011     PhotoSize thumb;
1012     string    file_name;
1013     string    mime_type;
1014     uint      file_size;
1015 }
1016 
1017 struct CallbackGame
1018 {
1019     // no fields
1020 }
1021 
1022 struct GameHighScore
1023 {
1024     uint  position;
1025     User  user;
1026     uint  score;
1027 }
1028 
1029 /******************************************************************/
1030 /*                        Telegram methods                        */
1031 /******************************************************************/
1032 
1033 mixin template TelegramMethod(string path, HTTPMethod method = HTTPMethod.POST)
1034 {
1035     package:
1036         immutable string _path       = path;
1037         HTTPMethod       _httpMethod = method;
1038 }
1039 
1040 /// UDA for telegram methods
1041 struct Method
1042 {
1043     string path;
1044 }
1045 
1046 struct GetUpdatesMethod
1047 {
1048     mixin TelegramMethod!"/getUpdates";
1049 
1050     int   offset;
1051     ubyte limit;
1052     uint  timeout;
1053 }
1054 
1055 struct SetWebhookMethod
1056 {
1057     mixin TelegramMethod!"/setWebhook";
1058 
1059     string             url;
1060     Nullable!InputFile certificate;
1061     uint               max_connections;
1062     string[]           allowed_updates;
1063 }
1064 
1065 struct DeleteWebhookMethod
1066 {
1067     mixin TelegramMethod!"/deleteWebhook";
1068 }
1069 
1070 struct GetWebhookInfoMethod
1071 {
1072     mixin TelegramMethod!("/getWebhookInfo", HTTPMethod.GET);
1073 }
1074 
1075 struct GetMeMethod
1076 {
1077     mixin TelegramMethod!("/getMe", HTTPMethod.GET);
1078 }
1079 
1080 struct SendMessageMethod
1081 {
1082     mixin TelegramMethod!"/sendMessage";
1083 
1084     string    chat_id;
1085     string    text;
1086     ParseMode parse_mode;
1087     bool      disable_web_page_preview;
1088     bool      disable_notification;
1089     uint      reply_to_message_id;
1090 
1091     ReplyMarkup reply_markup;
1092 }
1093 
1094 struct ForwardMessageMethod
1095 {
1096     mixin TelegramMethod!"/forwardMessage";
1097 
1098     string chat_id;
1099     string from_chat_id;
1100     bool   disable_notification;
1101     uint   message_id;
1102 }
1103 
1104 struct SendPhotoMethod
1105 {
1106     mixin TelegramMethod!"/sendPhoto";
1107 
1108     string      chat_id;
1109     string      photo;
1110     string      caption;
1111     ParseMode   parse_mode;
1112     bool        disable_notification;
1113     uint        reply_to_message_id;
1114     ReplyMarkup reply_markup;
1115 }
1116 
1117 struct SendAudioMethod
1118 {
1119     mixin TelegramMethod!"/sendAudio";
1120 
1121     string      chat_id;
1122     string      audio;
1123     string      caption;
1124     ParseMode   parse_mode;
1125     uint        duration;
1126     string      performer;
1127     string      title;
1128     bool        disable_notification;
1129     uint        reply_to_message_id;
1130     ReplyMarkup reply_markup;
1131 
1132 }
1133 
1134 struct SendDocumentMethod
1135 {
1136     mixin TelegramMethod!"/sendDocument";
1137 
1138     string      chat_id;
1139     string      document;
1140     string      caption;
1141     ParseMode   parse_mode;
1142     bool        disable_notification;
1143     uint        reply_to_message_id;
1144     ReplyMarkup reply_markup;
1145 }
1146 
1147 struct SendVideoMethod
1148 {
1149     mixin TelegramMethod!"/sendVideo";
1150 
1151     string      chat_id;
1152     string      video;
1153     uint        duration;
1154     uint        width;
1155     uint        height;
1156     string      caption;
1157     ParseMode   parse_mode;
1158     bool        supports_streaming;
1159     bool        disable_notification;
1160     uint        reply_to_message_id;
1161     ReplyMarkup reply_markup;
1162 }
1163 
1164 struct SendVoiceMethod
1165 {
1166     mixin TelegramMethod!"/sendVoice";
1167 
1168     string      chat_id;
1169     string      voice;
1170     string      caption;
1171     ParseMode   parse_mode;
1172     uint        duration;
1173     bool        disable_notification;
1174     uint        reply_to_message_id;
1175     ReplyMarkup reply_markup;
1176 }
1177 
1178 struct SendVideoNoteMethod
1179 {
1180     mixin TelegramMethod!"/sendVideoNote";
1181 
1182     string      chat_id;
1183     string      video_note;
1184     uint        duration;
1185     uint        length;
1186     bool        disable_notification;
1187     uint        reply_to_message_id;
1188     ReplyMarkup reply_markup;
1189 
1190 }
1191 
1192 struct SendMediaGroupMethod
1193 {
1194     mixin TelegramMethod!"/sendMediaGroup";
1195 
1196     string       chat_id;
1197     InputMedia[] media;
1198     bool         disable_notification;
1199     uint         reply_to_message_id;
1200 }
1201 
1202 struct SendLocationMethod
1203 {
1204     mixin TelegramMethod!"/sendLocation";
1205 
1206     string      chat_id;
1207     float       latitude;
1208     float       longitude;
1209     uint        live_period;
1210     bool        disable_notification;
1211     uint        reply_to_message_id;
1212     ReplyMarkup reply_markup;
1213 }
1214 
1215 struct EditMessageLiveLocationMethod
1216 {
1217     mixin TelegramMethod!"/editMessageLiveLocation";
1218 
1219     string      chat_id;
1220     uint        message_id;
1221     string      inline_message_id;
1222     float       latitude;
1223     float       longitude;
1224     ReplyMarkup reply_markup;
1225 }
1226 
1227 struct StopMessageLiveLocationMethod
1228 {
1229     mixin TelegramMethod!"/stopMessageLiveLocation";
1230 
1231     string      chat_id;
1232     uint        message_id;
1233     string      inline_message_id;
1234     ReplyMarkup reply_markup;
1235 }
1236 
1237 struct SendVenueMethod
1238 {
1239     mixin TelegramMethod!"/sendVenue";
1240 
1241     string      chat_id;
1242     float       latitude;
1243     float       longitude;
1244     string      title;
1245     string      address;
1246     string      foursquare_id;
1247     bool        disable_notification;
1248     uint        reply_to_message_id;
1249     ReplyMarkup reply_markup;
1250 }
1251 
1252 struct SendContactMethod
1253 {
1254     mixin TelegramMethod!"/sendContact";
1255 
1256     string      chat_id;
1257     string      phone_number;
1258     string      first_name;
1259     string      last_name;
1260     bool        disable_notification;
1261     uint        reply_to_message_id;
1262     ReplyMarkup reply_markup;
1263 }
1264 
1265 struct SendChatActionMethod
1266 {
1267     mixin TelegramMethod!"/sendChatAction";
1268 
1269     string chat_id;
1270     string action; // TODO enum
1271 }
1272 
1273 struct GetUserProfilePhotosMethod
1274 {
1275     mixin TelegramMethod!("/getUserProfilePhotos", HTTPMethod.GET);
1276 
1277     int  user_id;
1278     uint offset;
1279     uint limit;
1280 }
1281 
1282 struct GetFileMethod
1283 {
1284     mixin TelegramMethod!("/getFile", HTTPMethod.GET);
1285 
1286     string file_id;
1287 }
1288 
1289 struct KickChatMemberMethod
1290 {
1291     mixin TelegramMethod!"/kickChatMember";
1292 
1293     string chat_id;
1294     uint   user_id;
1295     uint   until_date;
1296 }
1297 
1298 struct UnbanChatMemberMethod
1299 {
1300     mixin TelegramMethod!"/unbanChatMember";
1301 
1302     string chat_id;
1303     uint   user_id;
1304 }
1305 
1306 struct RestrictChatMemberMethod
1307 {
1308     mixin TelegramMethod!"/restrictChatMember";
1309 
1310     string chat_id;
1311     uint   user_id;
1312     uint   until_date;
1313     bool   can_send_messages;
1314     bool   can_send_media_messages;
1315     bool   can_send_other_messages;
1316     bool   can_add_web_page_previews;
1317 }
1318 
1319 struct PromoteChatMemberMethod
1320 {
1321     mixin TelegramMethod!"/promoteChatMember";
1322 
1323     string chat_id;
1324     uint   user_id;
1325     bool   can_change_info;
1326     bool   can_post_messages;
1327     bool   can_edit_messages;
1328     bool   can_delete_messages;
1329     bool   can_invite_users;
1330     bool   can_restrict_members;
1331     bool   can_pin_messages;
1332     bool   can_promote_members;
1333 }
1334 
1335 struct ExportChatInviteLinkMethod
1336 {
1337     mixin TelegramMethod!"/exportChatInviteLink";
1338 
1339     string chat_id;
1340 }
1341 
1342 struct SetChatPhotoMethod
1343 {
1344     mixin TelegramMethod!"/setChatPhoto";
1345 
1346     string    chat_id;
1347     InputFile photo;
1348 
1349 }
1350 
1351 struct DeleteChatPhotoMethod
1352 {
1353     mixin TelegramMethod!"/deleteChatPhoto";
1354 
1355     string chat_id;
1356 }
1357 
1358 struct SetChatTitleMethod
1359 {
1360     mixin TelegramMethod!"/setChatTitle";
1361 
1362     string chat_id;
1363     string title;
1364 }
1365 
1366 struct SetChatDescriptionMethod
1367 {
1368     mixin TelegramMethod!"/setChatDescription";
1369 
1370     string chat_id;
1371     string description;
1372 }
1373 
1374 struct PinChatMessageMethod
1375 {
1376     mixin TelegramMethod!"/pinChatMessage";
1377 
1378     string chat_id;
1379     uint   message_id;
1380     bool   disable_notification;
1381 }
1382 
1383 struct UnpinChatMessageMethod
1384 {
1385     mixin TelegramMethod!"/unpinChatMessage";
1386 
1387     string chat_id;
1388 }
1389 
1390 struct LeaveChatMethod
1391 {
1392     mixin TelegramMethod!"/leaveChat";
1393 
1394     string chat_id;
1395 }
1396 
1397 struct GetChatMethod
1398 {
1399     mixin TelegramMethod!("/getChat", HTTPMethod.GET);
1400 
1401     string chat_id;
1402 }
1403 
1404 struct GetChatAdministratorsMethod
1405 {
1406     mixin TelegramMethod!("/getChatAdministrators", HTTPMethod.GET);
1407 
1408     string chat_id;
1409 }
1410 
1411 struct GetChatMembersCountMethod
1412 {
1413     mixin TelegramMethod!("/getChatMembersCount", HTTPMethod.GET);
1414 
1415     string chat_id;
1416 }
1417 
1418 struct GetChatMemberMethod
1419 {
1420     mixin TelegramMethod!("/getChatMember", HTTPMethod.GET);
1421 
1422     string chat_id;
1423     uint   user_id;
1424 }
1425 
1426 struct SetChatStickerSetMethod
1427 {
1428     mixin TelegramMethod!"/setChatStickerSet";
1429 
1430     string chat_id;
1431     string sticker_set_name;
1432 }
1433 
1434 struct DeleteChatStickerSetMethod
1435 {
1436     mixin TelegramMethod!"/deleteChatStickerSet";
1437 
1438     string chat_id;
1439 }
1440 
1441 struct AnswerCallbackQueryMethod
1442 {
1443     mixin TelegramMethod!"/answerCallbackQuery";
1444 
1445     string callback_query_id;
1446     string text;
1447     bool   show_alert;
1448     string url;
1449     uint   cache_time;
1450 }
1451 
1452 struct EditMessageTextMethod
1453 {
1454     mixin TelegramMethod!"/editMessageTextMethod";
1455 
1456     string      chat_id;
1457     uint        message_id;
1458     string      inline_message_id;
1459     string      text;
1460     ParseMode   parse_mode;
1461     bool        disable_web_page_preview;
1462     ReplyMarkup reply_markup;
1463 }
1464 
1465 struct EditMessageCaptionMethod
1466 {
1467     mixin TelegramMethod!"/editMessageCaptionMethod";
1468 
1469     string      chat_id;
1470     uint        message_id;
1471     string      inline_message_id;
1472     string      caption;
1473     ParseMode   parse_mode;
1474     ReplyMarkup reply_markup;
1475 }
1476 
1477 struct EditMessageReplyMarkupMethod
1478 {
1479     mixin TelegramMethod!"/editMessageReplyMarkupMethod";
1480 
1481     string      chat_id;
1482     uint        message_id;
1483     string      inline_message_id;
1484     ReplyMarkup reply_markup;
1485 }
1486 
1487 struct DeleteMessageMethod
1488 {
1489     mixin TelegramMethod!"/deleteMessageMethod";
1490 
1491     string chat_id;
1492     uint   message_id;
1493 }
1494 
1495 struct SendStickerMethod
1496 {
1497     mixin TelegramMethod!"/sendStickerMethod";
1498 
1499     string      chat_id;
1500     string      sticker; // TODO InputFile|string
1501     bool        disable_notification;
1502     uint        reply_to_message_id;
1503     ReplyMarkup reply_markup;
1504 }
1505 
1506 struct GetStickerSetMethod
1507 {
1508     mixin TelegramMethod!("/getStickerSetMethod", HTTPMethod.GET);
1509 
1510     string name;
1511 }
1512 
1513 struct UploadStickerFileMethod
1514 {
1515     mixin TelegramMethod!"/uploadStickerFileMethod";
1516 
1517     int       user_id;
1518     InputFile png_sticker;
1519 }
1520 
1521 struct CreateNewStickerSetMethod
1522 {
1523     mixin TelegramMethod!"/createNewStickerSetMethod";
1524 
1525     int          user_id;
1526     string       name;
1527     string       title;
1528     string       png_sticker; // TODO InputFile|string
1529     string       emojis;
1530     bool         contains_masks;
1531     MaskPosition mask_position;
1532 }
1533 
1534 struct AddStickerToSetMethod
1535 {
1536     mixin TelegramMethod!"/addStickerToSetMethod";
1537 
1538     int          user_id;
1539     string       name;
1540     string       png_sticker; // TODO InputFile|string
1541     string       emojis;
1542     MaskPosition mask_position;
1543 }
1544 
1545 struct SetStickerPositionInSetMethod
1546 {
1547     mixin TelegramMethod!"/setStickerPositionInSetMethod";
1548 
1549     string sticker;
1550     int    position;
1551 }
1552 
1553 struct DeleteStickerFromSetMethod
1554 {
1555     mixin TelegramMethod!"/deleteStickerFromSetMethod";
1556 
1557     string sticker;
1558 }
1559 
1560 struct AnswerInlineQueryMethod
1561 {
1562     mixin TelegramMethod!"/answerInlineQuery";
1563 
1564     string              inline_query_id;
1565     InlineQueryResult[] results;
1566     uint                cache_time;
1567     bool                is_personal;
1568     string              next_offset;
1569     string              switch_pm_text;
1570     string              switch_pm_parameter;
1571 }
1572 
1573 /******************************************************************/
1574 /*                          Telegram API                          */
1575 /******************************************************************/
1576 
1577 enum BaseApiUrl = "https://api.telegram.org/bot";
1578 
1579 class BotApi
1580 {
1581     private:
1582         string baseUrl;
1583         string apiUrl;
1584 
1585         ulong requestCounter = 1;
1586         uint maxUpdateId = 1;
1587 
1588         struct MethodResult(T)
1589         {
1590             bool   ok;
1591             T      result;
1592             ushort error_code;
1593             string description;
1594         }
1595 
1596     protected:
1597         HttpClient httpClient;
1598 
1599     public:
1600         this(string token, string baseUrl = BaseApiUrl, HttpClient httpClient = null)
1601         {
1602             this.baseUrl = baseUrl;
1603             this.apiUrl = baseUrl ~ token;
1604 
1605             if (httpClient is null) {
1606                 version(TelegaVibedDriver) {
1607                     import telega.drivers.vibe;
1608 
1609                     httpClient = new VibedHttpClient();
1610                 } else version(TelegaRequestsDriver) {
1611                     import telega.drivers.requests;
1612 
1613                     httpClient = new RequestsHttpClient();
1614                 } else {
1615                     assert(false, `No HTTP client is set, maybe you should enable "default" configuration?`);
1616                 }
1617             }
1618             this.httpClient = httpClient;
1619         }
1620 
1621         void updateProcessed(int updateId)
1622         {
1623             if (updateId >= maxUpdateId) {
1624                 maxUpdateId = updateId + 1;
1625             }
1626         }
1627 
1628         void updateProcessed(ref Update update)
1629         {
1630             updateProcessed(update.id);
1631         }
1632 
1633         T callMethod(T, M)(M method)
1634         {
1635             T result;
1636 
1637             logDiagnostic("[%d] Requesting %s", requestCounter, method._path);
1638 
1639             version(unittest)
1640             {
1641                 import std.stdio;
1642                 serializeToJsonString(method).writeln();
1643             } else {
1644                 string answer;
1645 
1646                 if (method._httpMethod == HTTPMethod.POST) {
1647                     string bodyJson = serializeToJsonString(method);
1648                     logDebugV("[%d] Sending body:\n  %s", requestCounter, bodyJson);
1649 
1650                     answer = httpClient.sendPostRequestJson(apiUrl ~ method._path, bodyJson);
1651                 } else {
1652                     answer = httpClient.sendGetRequest(apiUrl ~ method._path);
1653                 }
1654 
1655                 logDebugV("[%d] Data received:\n %s", requestCounter, answer);
1656 
1657                 auto json = answer.deserialize!(MethodResult!T);
1658 
1659                 enforce(json.ok == true, new TelegramBotApiException(json.error_code, json.description));
1660 
1661                 result = json.result;
1662                 requestCounter++;
1663             }
1664 
1665             return result;
1666         }
1667 
1668         Update[] getUpdates(ubyte limit = 5, uint timeout = 30)
1669         {
1670             GetUpdatesMethod m = {
1671                 offset:  maxUpdateId,
1672                 limit:   limit,
1673                 timeout: timeout,
1674             };
1675 
1676             return callMethod!(Update[], GetUpdatesMethod)(m);
1677         }
1678 
1679         bool setWebhook(string url)
1680         {
1681             SetWebhookMethod m = {
1682                 url : url
1683             };
1684 
1685             return setWebhook(m);
1686         }
1687 
1688         bool setWebhook(ref SetWebhookMethod m)
1689         {
1690             return callMethod!(bool, SetWebhookMethod)(m);
1691         }
1692 
1693         bool deleteWebhook()
1694         {
1695             DeleteWebhookMethod m = DeleteWebhookMethod();
1696 
1697             return callMethod!(bool, DeleteWebhookMethod)(m);
1698         }
1699 
1700         WebhookInfo getWebhookInfo()
1701         {
1702             GetWebhookInfoMethod m = GetWebhookInfoMethod();
1703 
1704             return callMethod!(WebhookInfo, GetWebhookInfoMethod)(m);
1705         }
1706 
1707         User getMe()
1708         {
1709             GetMeMethod m;
1710 
1711             return callMethod!(User, GetMeMethod)(m);
1712         }
1713 
1714         Message sendMessage(T)(T chatId, string text)
1715             if (isTelegramId!T)
1716         {
1717             SendMessageMethod m = {
1718                 text       : text,
1719             };
1720 
1721             static if (isIntegral!T) {
1722                 m.chat_id = chatId.to!string;
1723             } else {
1724                 m.chat_id = chatId;
1725             }
1726 
1727             return sendMessage(m);
1728         }
1729 
1730         Message sendMessage(ref SendMessageMethod m)
1731         {
1732             return callMethod!(Message, SendMessageMethod)(m);
1733         }
1734 
1735         Message forwardMessage(T1, T2)(T1 chatId, T2 fromChatId, uint messageId)
1736             if (isTelegramId!T1 && isTelegramId!T2)
1737         {
1738             ForwardMessageMethod m = {
1739                 message_id : messageId
1740             };
1741 
1742             static if (isIntegral!T1) {
1743                 m.chat_id = chatId.to!string;
1744             } else {
1745                 m.chat_id = chatId;
1746             }
1747 
1748             static if (isIntegral!T2) {
1749                 m.from_chat_id = fromChatId.to!string;
1750             } else {
1751                 m.from_chat_id = fromChatId;
1752             }
1753 
1754             return callMethod!(Message, ForwardMessageMethod)(m);
1755         }
1756 
1757         Message forwardMessage(ref ForwardMessageMethod m)
1758         {
1759             return callMethod!(Message, ForwardMessageMethod)(m);
1760         }
1761 
1762         Message sendPhoto(ref SendPhotoMethod m)
1763         {
1764             return callMethod!(Message, SendPhotoMethod)(m);
1765         }
1766 
1767         Message sendPhoto(T1)(T1 chatId, string photo)
1768             if (isTelegramId!T1)
1769         {
1770             SendPhotoMethod m = {
1771                 photo : photo
1772             };
1773 
1774             static if (isIntegral!T1) {
1775                 m.chat_id = chatId.to!string;
1776             } else {
1777                 m.chat_id = chatId;
1778             }
1779 
1780             return sendPhoto(m);
1781         }
1782 
1783         Message sendAudio(ref SendAudioMethod m)
1784         {
1785             return callMethod!(Message, SendAudioMethod)(m);
1786         }
1787 
1788         Message sendAudio(T1)(T1 chatId, string audio)
1789             if (isTelegramId!T1)
1790         {
1791             SendAudioMethod m = {
1792                 audio : audio
1793             };
1794 
1795             static if (isIntegral!T1) {
1796                 m.chat_id = chatId.to!string;
1797             } else {
1798                 m.chat_id = chatId;
1799             }
1800 
1801             return sendAudio(m);
1802         }
1803 
1804         Message sendDocument(ref SendDocumentMethod m)
1805         {
1806             return callMethod!(Message, SendDocumentMethod)(m);
1807         }
1808 
1809         Message sendDocument(T1)(T1 chatId, string document)
1810             if (isTelegramId!T1)
1811         {
1812             SendDocumentMethod m = {
1813                 document : document
1814             };
1815 
1816             static if (isIntegral!T1) {
1817                 m.chat_id = chatId.to!string;
1818             } else {
1819                 m.chat_id = chatId;
1820             }
1821 
1822             return sendDocument(m);
1823         }
1824 
1825         Message sendVideo(ref SendVideoMethod m)
1826         {
1827             return callMethod!(Message, SendVideoMethod)(m);
1828         }
1829 
1830         Message sendVideo(T1)(T1 chatId, string video)
1831             if (isTelegramId!T1)
1832         {
1833             SendVideoMethod m = {
1834                 video : video
1835             };
1836 
1837             static if (isIntegral!T1) {
1838                 m.chat_id = chatId.to!string;
1839             } else {
1840                 m.chat_id = chatId;
1841             }
1842 
1843             return sendVideo(m);
1844         }
1845 
1846         Message sendVoice(ref SendVoiceMethod m)
1847         {
1848             return callMethod!(Message, SendVoiceMethod)(m);
1849         }
1850 
1851         Message sendVoice(T1)(T1 chatId, string voice)
1852             if (isTelegramId!T1)
1853         {
1854             SendVoiceMethod m = {
1855                 voice : voice
1856             };
1857 
1858             static if (isIntegral!T1) {
1859                 m.chat_id = chatId.to!string;
1860             } else {
1861                 m.chat_id = chatId;
1862             }
1863 
1864             return sendVoice(m);
1865         }
1866 
1867         Message sendVideoNote(ref SendVideoNoteMethod m)
1868         {
1869             return callMethod!(Message, SendVideoNoteMethod)(m);
1870         }
1871 
1872         Message sendVideoNote(T1)(T1 chatId, string videoNote)
1873             if (isTelegramId!T1)
1874         {
1875             SendVideoNoteMethod m = {
1876                 video_note : videoNote
1877             };
1878 
1879             static if (isIntegral!T1) {
1880                 m.chat_id = chatId.to!string;
1881             } else {
1882                 m.chat_id = chatId;
1883             }
1884 
1885             return sendVideoNote(m);
1886         }
1887 
1888         Message sendMediaGroup(ref SendMediaGroupMethod m)
1889         {
1890             return callMethod!(Message, SendMediaGroupMethod)(m);
1891         }
1892 
1893         Message sendMediaGroup(T1)(T1 chatId, InputMedia[] media)
1894             if (isTelegramId!T1)
1895         {
1896             SendMediaGroupMethod m = {
1897                 media : media
1898             };
1899 
1900             static if (isIntegral!T1) {
1901                 m.chat_id = chatId.to!string;
1902             } else {
1903                 m.chat_id = chatId;
1904             }
1905 
1906             return sendMediaGroup(m);
1907         }
1908 
1909         Message sendLocation(ref SendLocationMethod m)
1910         {
1911             return callMethod!(Message, SendLocationMethod)(m);
1912         }
1913 
1914         Message sendLocation(T1)(T1 chatId, float latitude, float longitude)
1915             if (isTelegramId!T1)
1916         {
1917             SendLocationMethod m = {
1918                 latitude : latitude,
1919                 longitude : longitude,
1920             };
1921 
1922             static if (isIntegral!T1) {
1923                 m.chat_id = chatId.to!string;
1924             } else {
1925                 m.chat_id = chatId;
1926             }
1927 
1928             return sendLocation(m);
1929         }
1930 
1931         Nullable!Message editMessageLiveLocation(ref EditMessageLiveLocationMethod m)
1932         {
1933             return callMethod!(Nullable!Message, EditMessageLiveLocationMethod)(m);
1934         }
1935 
1936         Nullable!Message editMessageLiveLocation(string inlineMessageId, float latitude, float longitude)
1937         {
1938             EditMessageLiveLocationMethod m = {
1939                 inline_message_id : inlineMessageId,
1940                 latitude : latitude,
1941                 longitude : longitude
1942             };
1943 
1944             return editMessageLiveLocation(m);
1945         }
1946 
1947         Nullable!Message editMessageLiveLocation(T1)(T1 chatId, uint messageId, float latitude, float longitude)
1948             if (isTelegramId!T1)
1949         {
1950             EditMessageLiveLocationMethod m = {
1951                 message_id : messageId,
1952                 latitude : latitude,
1953                 longitude : longitude
1954             };
1955 
1956             static if (isIntegral!T1) {
1957                 m.chat_id = chatId.to!string;
1958             } else {
1959                 m.chat_id = chatId;
1960             }
1961 
1962             return editMessageLiveLocation(m);
1963         }
1964 
1965         Nullable!Message stopMessageLiveLocation(ref StopMessageLiveLocationMethod m)
1966         {
1967             return callMethod!(Nullable!Message, StopMessageLiveLocationMethod)(m);
1968         }
1969 
1970         Nullable!Message stopMessageLiveLocation(string inlineMessageId)
1971         {
1972             StopMessageLiveLocationMethod m = {
1973                 inline_message_id : inlineMessageId
1974             };
1975 
1976             return stopMessageLiveLocation(m);
1977         }
1978 
1979         Nullable!Message stopMessageLiveLocation(T1)(T1 chatId, uint messageId)
1980             if (isTelegramId!T1)
1981         {
1982             StopMessageLiveLocationMethod m = {
1983                 message_id : messageId
1984             };
1985 
1986             static if (isIntegral!T1) {
1987                 m.chat_id = chatId.to!string;
1988             } else {
1989                 m.chat_id = chatId;
1990             }
1991 
1992             return stopMessageLiveLocation(m);
1993         }
1994 
1995         Message sendVenue(ref SendVenueMethod m)
1996         {
1997             return callMethod!(Message, SendVenueMethod)(m);
1998         }
1999 
2000         Message sendVenue(T1)(T1 chatId, float latitude, float longitude,
2001             string title, string address)
2002             if (isTelegramId!T1)
2003         {
2004             SendVenueMethod m = {
2005                 latitude : latitude,
2006                 longitude : longitude,
2007                 title : title,
2008                 address : address
2009             };
2010 
2011             static if (isIntegral!T1) {
2012                 m.chat_id = chatId.to!string;
2013             } else {
2014                 m.chat_id = chatId;
2015             }
2016 
2017             return sendVenue(m);
2018         }
2019 
2020         Message sendContact(ref SendContactMethod m)
2021         {
2022             return callMethod!(Message, SendContactMethod)(m);
2023         }
2024 
2025         Message sendContact(T1)(T1 chatId, string phone_number, string first_name)
2026             if (isTelegramId!T1)
2027         {
2028             SendContactMethod m = {
2029                 phone_number : phone_number,
2030                 first_name : first_name
2031             };
2032 
2033             static if (isIntegral!T1) {
2034                 m.chat_id = chatId.to!string;
2035             } else {
2036                 m.chat_id = chatId;
2037             }
2038 
2039             return sendContact(m);
2040         }
2041 
2042         bool sendChatAction(ref SendChatActionMethod m)
2043         {
2044             return callMethod!(bool, SendChatActionMethod)(m);
2045         }
2046 
2047         bool sendChatAction(T1)(T1 chatId, string action)
2048             if (isTelegramId!T1)
2049         {
2050             SendChatActionMethod m = {
2051                 action : action
2052             };
2053 
2054             static if (isIntegral!T1) {
2055                 m.chat_id = chatId.to!string;
2056             } else {
2057                 m.chat_id = chatId;
2058             }
2059 
2060             return sendChatAction(m);
2061         }
2062 
2063         UserProfilePhotos getUserProfilePhotos(ref GetUserProfilePhotosMethod m)
2064         {
2065             return callMethod!(UserProfilePhotos, GetUserProfilePhotosMethod)(m);
2066         }
2067 
2068         UserProfilePhotos getUserProfilePhotos(int userId)
2069         {
2070             GetUserProfilePhotosMethod m = {
2071                 user_id : userId
2072             };
2073 
2074             return getUserProfilePhotos(m);
2075         }
2076 
2077         File getFile(ref GetFileMethod m)
2078         {
2079             return callMethod!(File, GetFileMethod)(m);
2080         }
2081 
2082         File getFile(string fileId)
2083         {
2084             GetFileMethod m = {
2085                 file_id : fileId
2086             };
2087 
2088             return getFile(m);
2089         }
2090 
2091         bool kickChatMember(ref KickChatMemberMethod m)
2092         {
2093             return callMethod!(bool, KickChatMemberMethod)(m);
2094         }
2095 
2096         bool kickChatMember(T1)(T1 chatId, int userId)
2097             if(isTelegramId!T1)
2098         {
2099             KickChatMemberMethod m = {
2100                 user_id : userId
2101             };
2102 
2103             static if (isIntegral!T1) {
2104                 m.chat_id = chatId.to!string;
2105             } else {
2106                 m.chat_id = chatId;
2107             }
2108 
2109             return kickChatMember(m);
2110         }
2111 
2112         bool unbanChatMember(ref UnbanChatMemberMethod m)
2113         {
2114             return callMethod!(bool, UnbanChatMemberMethod)(m);
2115         }
2116 
2117         bool unbanChatMember(T1)(T1 chatId, int userId)
2118             if(isTelegramId!T1)
2119         {
2120             UnbanChatMemberMethod m = {
2121                 user_id : userId
2122             };
2123 
2124             static if (isIntegral!T1) {
2125                 m.chat_id = chatId.to!string;
2126             } else {
2127                 m.chat_id = chatId;
2128             }
2129 
2130             return unbanChatMember(m);
2131         }
2132 
2133         bool restrictChatMember(ref RestrictChatMemberMethod m)
2134         {
2135             return callMethod!bool(m);
2136         }
2137 
2138         bool restrictChatMember(T1)(T1 chatId, int userId)
2139             if(isTelegramId!T1)
2140         {
2141             RestrictChatMemberMethod m = {
2142                 user_id : userId
2143             };
2144 
2145             static if (isIntegral!T1) {
2146                 m.chat_id = chatId.to!string;
2147             } else {
2148                 m.chat_id = chatId;
2149             }
2150 
2151             return restrictChatMember(m);
2152         }
2153 
2154         bool promoteChatMember(ref PromoteChatMemberMethod m)
2155         {
2156             return callMethod!bool(m);
2157         }
2158 
2159         bool promoteChatMember(T1)(T1 chatId, int userId)
2160             if(isTelegramId!T1)
2161         {
2162             PromoteChatMemberMethod m = {
2163                 user_id : userId
2164             };
2165 
2166             static if (isIntegral!T1) {
2167                 m.chat_id = chatId.to!string;
2168             } else {
2169                 m.chat_id = chatId;
2170             }
2171 
2172             return promoteChatMember(m);
2173         }
2174 
2175         string exportChatInviteLink(ref ExportChatInviteLinkMethod m)
2176         {
2177             return callMethod!string(m);
2178         }
2179 
2180         string exportChatInviteLink(T1)(T1 chatId)
2181             if(isTelegramId!T1)
2182         {
2183             ExportChatInviteLinkMethod m;
2184 
2185             static if (isIntegral!T1) {
2186                 m.chat_id = chatId.to!string;
2187             } else {
2188                 m.chat_id = chatId;
2189             }
2190 
2191             return exportChatInviteLink(m);
2192         }
2193 
2194         bool setChatPhoto(ref SetChatPhotoMethod m)
2195         {
2196             return callMethod!bool(m);
2197         }
2198 
2199         bool setChatPhoto(T1)(T1 chatId, InputFile photo)
2200             if (isTelegramId!T1)
2201         {
2202             SetChatPhotoMethod m = {
2203                 photo : photo
2204             };
2205 
2206             static if (isIntegral!T1) {
2207                 m.chat_id = chatId.to!string;
2208             } else {
2209                 m.chat_id = chatId;
2210             }
2211 
2212             return setChatPhoto(m);
2213         }
2214 
2215         bool deleteChatPhoto(ref DeleteChatPhotoMethod m)
2216         {
2217             return callMethod!bool(m);
2218         }
2219 
2220         bool deleteChatPhoto(T1)(T1 chatId)
2221             if (isTelegramId!T1)
2222         {
2223             DeleteChatPhotoMethod m;
2224 
2225             static if (isIntegral!T1) {
2226                 m.chat_id = chatId.to!string;
2227             } else {
2228                 m.chat_id = chatId;
2229             }
2230 
2231             return deleteChatPhoto(m);
2232         }
2233 
2234         bool setChatTitle(ref SetChatTitleMethod m)
2235         {
2236             return callMethod!bool(m);
2237         }
2238 
2239         bool setChatTitle(T1)(T1 chatId, string title)
2240             if (isTelegramId!T1)
2241         {
2242             SetChatTitleMethod m = {
2243                 title : title
2244             };
2245 
2246             static if (isIntegral!T1) {
2247                 m.chat_id = chatId.to!string;
2248             } else {
2249                 m.chat_id = chatId;
2250             }
2251 
2252             return setChatTitle(m);
2253         }
2254 
2255         bool setChatDescription(ref SetChatDescriptionMethod m)
2256         {
2257             return callMethod!bool(m);
2258         }
2259 
2260         bool setChatDescription(T1)(T1 chatId, string description)
2261             if (isTelegramId!T1)
2262         {
2263             SetChatDescriptionMethod m = {
2264                 description : description
2265             };
2266 
2267             static if (isIntegral!T1) {
2268                 m.chat_id = chatId.to!string;
2269             } else {
2270                 m.chat_id = chatId;
2271             }
2272 
2273             return setChatDescription(m);
2274         }
2275 
2276         bool pinChatMessage(ref PinChatMessageMethod m)
2277         {
2278             return callMethod!bool(m);
2279         }
2280 
2281         bool pinChatMessage(T1)(T1 chatId, uint messageId)
2282             if (isTelegramId!T1)
2283         {
2284             PinChatMessageMethod m = {
2285                 message_id : messageId
2286             };
2287 
2288             static if (isIntegral!T1) {
2289                 m.chat_id = chatId.to!string;
2290             } else {
2291                 m.chat_id = chatId;
2292             }
2293 
2294             return pinChatMessage(m);
2295         }
2296 
2297         bool unpinChatMessage(ref UnpinChatMessageMethod m)
2298         {
2299             return callMethod!bool(m);
2300         }
2301 
2302         bool unpinChatMessage(T1)(T1 chatId)
2303             if (isTelegramId!T1)
2304         {
2305             UnpinChatMessageMethod m;
2306 
2307             static if (isIntegral!T1) {
2308                 m.chat_id = chatId.to!string;
2309             } else {
2310                 m.chat_id = chatId;
2311             }
2312 
2313             return unpinChatMessage(m);
2314         }
2315 
2316         bool leaveChat(ref LeaveChatMethod m)
2317         {
2318             return callMethod!bool(m);
2319         }
2320 
2321         bool leaveChat(T1)(T1 chatId)
2322             if (isTelegramId!T1)
2323         {
2324             LeaveChatMethod m;
2325 
2326             static if (isIntegral!T1) {
2327                 m.chat_id = chatId.to!string;
2328             } else {
2329                 m.chat_id = chatId;
2330             }
2331 
2332             return leaveChat(m);
2333         }
2334 
2335         Chat getChat(ref GetChatMethod m)
2336         {
2337             return callMethod!Chat(m);
2338         }
2339 
2340         Chat getChat(T1)(T1 chatId)
2341             if (isTelegramId!T1)
2342         {
2343             GetChatMethod m;
2344 
2345             static if (isIntegral!T1) {
2346                 m.chat_id = chatId.to!string;
2347             } else {
2348                 m.chat_id = chatId;
2349             }
2350 
2351             return getChat(m);
2352         }
2353 
2354         ChatMember getChatAdministrators(ref GetChatAdministratorsMethod m)
2355         {
2356             return callMethod!ChatMember(m);
2357         }
2358 
2359         ChatMember getChatAdministrators(T1)(T1 chatId)
2360             if (isTelegramId!T1)
2361         {
2362             GetChatAdministratorsMethod m;
2363 
2364             static if (isIntegral!T1) {
2365                 m.chat_id = chatId.to!string;
2366             } else {
2367                 m.chat_id = chatId;
2368             }
2369 
2370             return getChatAdministrators(m);
2371         }
2372 
2373         uint getChatMembersCount(ref GetChatMembersCountMethod m)
2374         {
2375             return callMethod!uint(m);
2376         }
2377 
2378         uint getChatMembersCount(T1)(T1 chatId)
2379             if (isTelegramId!T1)
2380         {
2381             GetChatMembersCountMethod m;
2382 
2383             static if (isIntegral!T1) {
2384                 m.chat_id = chatId.to!string;
2385             } else {
2386                 m.chat_id = chatId;
2387             }
2388 
2389             return getChatMembersCount(m);
2390         }
2391 
2392         ChatMember getChatMember(ref GetChatMemberMethod m)
2393         {
2394             return callMethod!ChatMember(m);
2395         }
2396 
2397         ChatMember getChatMember(T1)(T1 chatId, int userId)
2398             if (isTelegramId!T1)
2399         {
2400             GetChatMemberMethod m = {
2401                 user_id : userId
2402             };
2403 
2404             static if (isIntegral!T1) {
2405                 m.chat_id = chatId.to!string;
2406             } else {
2407                 m.chat_id = chatId;
2408             }
2409 
2410             return getChatMember(m);
2411         }
2412 
2413         bool setChatStickerSet(ref SetChatStickerSetMethod m)
2414         {
2415             return callMethod!bool(m);
2416         }
2417 
2418         bool setChatStickerSet(T1)(T1 chatId, string stickerSetName)
2419             if (isTelegramId!T1)
2420         {
2421             SetChatStickerSetMethod m = {
2422                 sticker_set_name : stickerSetName
2423             };
2424 
2425             static if (isIntegral!T1) {
2426                 m.chat_id = chatId.to!string;
2427             } else {
2428                 m.chat_id = chatId;
2429             }
2430 
2431             return setChatStickerSet(m);
2432         }
2433 
2434         bool deleteChatStickerSet(ref DeleteChatStickerSetMethod m)
2435         {
2436             return callMethod!bool(m);
2437         }
2438 
2439         bool deleteChatStickerSet(T1)(T1 chatId)
2440             if (isTelegramId!T1)
2441         {
2442             DeleteChatStickerSetMethod m;
2443 
2444             static if (isIntegral!T1) {
2445                 m.chat_id = chatId.to!string;
2446             } else {
2447                 m.chat_id = chatId;
2448             }
2449 
2450             return deleteChatStickerSet(m);
2451         }
2452 
2453         bool answerCallbackQuery(ref AnswerCallbackQueryMethod m)
2454         {
2455             return callMethod!bool(m);
2456         }
2457 
2458         bool answerCallbackQuery(string callbackQueryId)
2459         {
2460             AnswerCallbackQueryMethod m = {
2461                 callback_query_id : callbackQueryId
2462             };
2463 
2464             return answerCallbackQuery(m);
2465         }
2466 
2467         bool editMessageText(ref EditMessageTextMethod m)
2468         {
2469             return callMethod!bool(m);
2470         }
2471 
2472         bool editMessageText(T1)(T1 chatId, uint messageId, string text)
2473             if (isTelegramId!T1)
2474         {
2475             EditMessageTextMethod m = {
2476                 message_id : messageId,
2477                 text : text
2478             };
2479 
2480             static if (isIntegral!T1) {
2481                 m.chat_id = chatId.to!string;
2482             } else {
2483                 m.chat_id = chatId;
2484             }
2485 
2486             return editMessageText(m);
2487         }
2488 
2489         bool editMessageText(string inlineMessageId, string text)
2490         {
2491             EditMessageTextMethod m = {
2492                 inline_message_id : inlineMessageId,
2493                 text : text
2494             };
2495 
2496             return editMessageText(m);
2497         }
2498 
2499         bool editMessageCaption(ref EditMessageCaptionMethod m)
2500         {
2501             return callMethod!bool(m);
2502         }
2503 
2504         bool editMessageCaption(T1)(T1 chatId, uint messageId, string caption = null)
2505             if (isTelegramId!T1)
2506         {
2507             EditMessageCaptionMethod m = {
2508                 message_id : messageId,
2509                 caption : caption
2510             };
2511 
2512             static if (isIntegral!T1) {
2513                 m.chat_id = chatId.to!string;
2514             } else {
2515                 m.chat_id = chatId;
2516             }
2517 
2518             return editMessageCaption(m);
2519         }
2520 
2521         bool editMessageCaption(string inlineMessageId, string caption = null)
2522         {
2523             EditMessageCaptionMethod m = {
2524                 inline_message_id : inlineMessageId,
2525                 caption : caption
2526             };
2527 
2528             return editMessageCaption(m);
2529         }
2530 
2531         bool editMessageReplyMarkup(ref EditMessageReplyMarkupMethod m)
2532         {
2533             return callMethod!bool(m);
2534         }
2535 
2536         bool editMessageReplyMarkup(T1, T2)(T1 chatId, uint messageId, T2 replyMarkup)
2537             if (isTelegramId!T1 && isReplyMarkup!T2)
2538         {
2539             EditMessageReplyMarkupMethod m = {
2540                 message_id : messageId
2541             };
2542 
2543             m.reply_markup = replyMarkup;
2544 
2545             static if (isIntegral!T1) {
2546                 m.chat_id = chatId.to!string;
2547             } else {
2548                 m.chat_id = chatId;
2549             }
2550 
2551             return editMessageReplyMarkup(m);
2552         }
2553 
2554         bool editMessageReplyMarkup(string inlineMessageId, Nullable!ReplyMarkup replyMarkup)
2555         {
2556             EditMessageReplyMarkupMethod m = {
2557                 inline_message_id : inlineMessageId,
2558                 reply_markup : replyMarkup
2559             };
2560 
2561             return editMessageReplyMarkup(m);
2562         }
2563 
2564         bool deleteMessage(ref DeleteMessageMethod m)
2565         {
2566             return callMethod!bool(m);
2567         }
2568 
2569         bool deleteMessage(T1)(T1 chatId, uint messageId)
2570             if (isTelegramId!T1)
2571         {
2572             DeleteMessageMethod m = {
2573                 message_id : messageId
2574             };
2575 
2576             static if (isIntegral!T1) {
2577                 m.chat_id = chatId.to!string;
2578             } else {
2579                 m.chat_id = chatId;
2580             }
2581 
2582             return deleteMessage(m);
2583         }
2584 
2585         Message sendSticker(ref SendStickerMethod m)
2586         {
2587             return callMethod!Message(m);
2588         }
2589 
2590         // TODO sticker is InputFile|string
2591         Message sendSticker(T1)(T1 chatId, string sticker)
2592             if (isTelegramId!T1)
2593         {
2594             SendStickerMethod m = {
2595                 sticker : sticker
2596             };
2597 
2598             static if (isIntegral!T1) {
2599                 m.chat_id = chatId.to!string;
2600             } else {
2601                 m.chat_id = chatId;
2602             }
2603 
2604             return sendSticker(m);
2605         }
2606 
2607         StickerSet getStickerSet(ref GetStickerSetMethod m)
2608         {
2609             return callMethod!StickerSet(m);
2610         }
2611 
2612         StickerSet getStickerSet(string name)
2613         {
2614             GetStickerSetMethod m = {
2615                 name : name
2616             };
2617 
2618             return getStickerSet(m);
2619         }
2620 
2621         File uploadStickerFile(ref UploadStickerFileMethod m)
2622         {
2623             return callMethod!File(m);
2624         }
2625 
2626         File uploadStickerFile(int userId, InputFile pngSticker)
2627         {
2628             UploadStickerFileMethod m = {
2629                 user_id : userId,
2630                 png_sticker : pngSticker
2631             };
2632 
2633             return uploadStickerFile(m);
2634         }
2635 
2636         bool createNewStickerSet(ref CreateNewStickerSetMethod m)
2637         {
2638             return callMethod!bool(m);
2639         }
2640 
2641         // TODO pngSticker is InputFile|string
2642         bool createNewStickerSet(int userId, string name, string title, string pngSticker, string emojis)
2643         {
2644             CreateNewStickerSetMethod m = {
2645                 user_id : userId,
2646                 name : name,
2647                 title : title,
2648                 png_sticker : pngSticker,
2649                 emojis : emojis
2650             };
2651 
2652             return createNewStickerSet(m);
2653         }
2654 
2655         bool addStickerToSet(ref AddStickerToSetMethod m)
2656         {
2657             return callMethod!bool(m);
2658         }
2659 
2660         bool addStickerToSet(int userId, string name, string pngSticker, string emojis)
2661         {
2662             AddStickerToSetMethod m = {
2663                 user_id : userId,
2664                 name : name,
2665                 png_sticker : pngSticker,
2666                 emojis : emojis
2667             };
2668 
2669             return addStickerToSet(m);
2670         }
2671 
2672         bool setStickerPositionInSet(ref SetStickerPositionInSetMethod m)
2673         {
2674             return callMethod!bool(m);
2675         }
2676 
2677         bool setStickerPositionInSet(string sticker, uint position)
2678         {
2679             SetStickerPositionInSetMethod m = {
2680                 sticker : sticker,
2681                 position : position
2682             };
2683 
2684             return setStickerPositionInSet(m);
2685         }
2686 
2687         bool deleteStickerFromSet(ref DeleteStickerFromSetMethod m)
2688         {
2689             return callMethod!bool(m);
2690         }
2691 
2692         bool deleteStickerFromSet(string sticker)
2693         {
2694             SetStickerPositionInSetMethod m = {
2695                 sticker : sticker
2696             };
2697 
2698             return setStickerPositionInSet(m);
2699         }
2700 
2701         bool answerInlineQuery(ref AnswerInlineQueryMethod m)
2702         {
2703             return callMethod!bool(m);
2704         }
2705 
2706         bool answerInlineQuery(string inlineQueryId, InlineQueryResult[] results)
2707         {
2708             AnswerInlineQueryMethod m = {
2709                 inline_query_id : inlineQueryId,
2710                 results : results
2711             };
2712 
2713             return answerInlineQuery(m);
2714         }
2715 
2716         unittest
2717         {
2718             class BotApiMock : BotApi
2719             {
2720                 this(string token)
2721                 {
2722                     super(token);
2723                 }
2724 
2725                 T callMethod(T, M)(M method)
2726                 {
2727                     T result;
2728 
2729                     logDiagnostic("[%d] Requesting %s", requestCounter, method.name);
2730 
2731                     return result;
2732                 }
2733             }
2734 
2735             auto api = new BotApiMock(null);
2736 
2737             api.getUpdates(5,30);
2738             api.setWebhook("https://webhook.url");
2739             api.deleteWebhook();
2740             api.getWebhookInfo();
2741             api.getMe();
2742             api.sendMessage("chat-id", "hello");
2743             api.forwardMessage("chat-id", "from-chat-id", 123);
2744             api.sendPhoto("chat-id", "photo-url");
2745             api.sendAudio("chat-id", "audio-url");
2746             api.sendDocument("chat-id", "document-url");
2747             api.sendVideo("chat-id", "video-url");
2748             api.sendVoice("chat-id", "voice-url");
2749             api.sendVideoNote("chat-id", "video-note-url");
2750             api.sendMediaGroup("chat-id", []);
2751             api.sendLocation("chat-id", 123, 123);
2752             api.editMessageLiveLocation("chat-id", 1, 1.23, 4.56);
2753             api.editMessageLiveLocation("inline-message-id", 1.23, 4.56);
2754             api.stopMessageLiveLocation("chat-id", 1);
2755             api.stopMessageLiveLocation("inline-message-id");
2756             api.sendVenue("chat-id", 123, 123, "title", "address");
2757             api.sendContact("chat-id", "+123", "First Name");
2758             api.sendChatAction("chat-id", "typing");
2759             api.getUserProfilePhotos(1);
2760             api.getFile("file-id");
2761             api.kickChatMember("chat-id", 1);
2762             api.unbanChatMember("chat-id", 1);
2763             api.restrictChatMember("chat-id", 1);
2764             api.promoteChatMember("chat-id", 1);
2765             api.exportChatInviteLink("chat-id");
2766             api.setChatPhoto("chat-id", InputFile());
2767             api.deleteChatPhoto("chat-id");
2768             api.setChatTitle("chat-id", "chat-title");
2769             api.setChatDescription("chat-id", "chat-description");
2770             api.pinChatMessage("chat-id", 1);
2771             api.unpinChatMessage("chat-id");
2772             api.leaveChat("chat-id");
2773             api.getChat("chat-id");
2774             api.getChatAdministrators("chat-id");
2775             api.getChatMembersCount("chat-id");
2776             api.getChatMember("chat-id", 1);
2777             api.setChatStickerSet("chat-id", "sticker-set");
2778             api.deleteChatStickerSet("chat-id");
2779             api.answerCallbackQuery("callback-query-id");
2780             api.editMessageText("chat-id", 123, "new text");
2781             api.editMessageText("inline-message-id", "new text");
2782             api.editMessageCaption("chat-id", 123, "new caption");
2783             api.editMessageCaption("chat-id", 123, null);
2784             api.editMessageCaption("inline-message-id", "new caption");
2785             api.editMessageCaption("inline-message-id", null);
2786 
2787             api.editMessageReplyMarkup("chat-id", 123, ForceReply());
2788             api.editMessageReplyMarkup("chat-id", 123, ReplyKeyboardMarkup());
2789             api.editMessageReplyMarkup("chat-id", 123, ReplyKeyboardRemove());
2790             api.editMessageReplyMarkup("chat-id", 123, InlineKeyboardMarkup());
2791             api.editMessageReplyMarkup("chat-id", 123, ReplyMarkup());
2792 
2793             api.deleteMessage("chat-id", 123);
2794             api.sendSticker("chat-id", "sticker");
2795             api.getStickerSet("sticker-set");
2796             api.uploadStickerFile(1, InputFile());
2797             api.createNewStickerSet(1, "name", "title", "png-sticker", "emojis");
2798             api.addStickerToSet(1, "name", "png-sticker", "emojis");
2799             api.setStickerPositionInSet("sticker", 42);
2800             api.deleteStickerFromSet("sticker");
2801 
2802             InlineQueryResult[] iqr = new InlineQueryResult[20];
2803 
2804             iqr[0] = InlineQueryResultArticle();
2805             iqr[1] = InlineQueryResultPhoto();
2806             iqr[2] = InlineQueryResultGif();
2807             iqr[3] = InlineQueryResultMpeg4Gif();
2808             iqr[4] = InlineQueryResultVideo();
2809             iqr[5] = InlineQueryResultAudio();
2810             iqr[6] = InlineQueryResultVoice();
2811             iqr[7] = InlineQueryResultDocument();
2812             iqr[8] = InlineQueryResultLocation();
2813             iqr[9] = InlineQueryResultVenue();
2814             iqr[10] = InlineQueryResultContact();
2815             iqr[11] = InlineQueryResultGame();
2816             iqr[12] = InlineQueryResultCachedPhoto();
2817             iqr[13] = InlineQueryResultCachedGif();
2818             iqr[14] = InlineQueryResultCachedMpeg4Gif();
2819             iqr[15] = InlineQueryResultCachedSticker();
2820             iqr[16] = InlineQueryResultCachedDocument();
2821             iqr[17] = InlineQueryResultCachedVideo();
2822             iqr[18] = InlineQueryResultCachedVoice();
2823             iqr[19] = InlineQueryResultCachedAudio();
2824 
2825             api.answerInlineQuery("answer-inline-query", iqr);
2826         }
2827 }