all repos — telegram-bot-api @ a7b8af6adbdae556dab8deca6d6560961eb41f24

Golang bindings for the Telegram Bot API

methods.go (view raw)

  1package main
  2
  3import (
  4	"bytes"
  5	"encoding/json"
  6	"io"
  7	"io/ioutil"
  8	"log"
  9	"mime/multipart"
 10	"net/http"
 11	"net/url"
 12	"os"
 13	"strconv"
 14)
 15
 16const (
 17	CHAT_TYPING          = "typing"
 18	CHAT_UPLOAD_PHOTO    = "upload_photo"
 19	CHAT_RECORD_VIDEO    = "record_video"
 20	CHAT_UPLOAD_VIDEO    = "upload_video"
 21	CHAT_RECORD_AUDIO    = "record_audio"
 22	CHAT_UPLOAD_AUDIO    = "upload_audio"
 23	CHAT_UPLOAD_DOCUMENT = "upload_document"
 24	CHAT_FIND_LOCATION   = "find_location"
 25)
 26
 27type BotConfig struct {
 28	token string
 29	debug bool
 30}
 31
 32type BotApi struct {
 33	config BotConfig
 34}
 35
 36func NewBotApi(config BotConfig) *BotApi {
 37	return &BotApi{
 38		config: config,
 39	}
 40}
 41
 42func (bot *BotApi) makeRequest(endpoint string, params url.Values) (ApiResponse, error) {
 43	resp, err := http.PostForm("https://api.telegram.org/bot"+bot.config.token+"/"+endpoint, params)
 44	defer resp.Body.Close()
 45	if err != nil {
 46		return ApiResponse{}, err
 47	}
 48
 49	bytes, err := ioutil.ReadAll(resp.Body)
 50	if err != nil {
 51		return ApiResponse{}, err
 52	}
 53
 54	if bot.config.debug {
 55		log.Println(string(bytes[:]))
 56	}
 57
 58	var apiResp ApiResponse
 59	json.Unmarshal(bytes, &apiResp)
 60
 61	return apiResp, nil
 62}
 63
 64func (bot *BotApi) uploadFile(endpoint string, params map[string]string, fieldname string, filename string) (ApiResponse, error) {
 65	var b bytes.Buffer
 66	w := multipart.NewWriter(&b)
 67
 68	f, err := os.Open(filename)
 69	if err != nil {
 70		return ApiResponse{}, err
 71	}
 72
 73	fw, err := w.CreateFormFile(fieldname, filename)
 74	if err != nil {
 75		return ApiResponse{}, err
 76	}
 77
 78	if _, err = io.Copy(fw, f); err != nil {
 79		return ApiResponse{}, err
 80	}
 81
 82	for key, val := range params {
 83		if fw, err = w.CreateFormField(key); err != nil {
 84			return ApiResponse{}, err
 85		}
 86
 87		if _, err = fw.Write([]byte(val)); err != nil {
 88			return ApiResponse{}, err
 89		}
 90	}
 91
 92	w.Close()
 93
 94	req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.config.token+"/"+endpoint, &b)
 95	if err != nil {
 96		return ApiResponse{}, err
 97	}
 98
 99	req.Header.Set("Content-Type", w.FormDataContentType())
100
101	client := &http.Client{}
102	res, err := client.Do(req)
103	if err != nil {
104		return ApiResponse{}, err
105	}
106
107	bytes, err := ioutil.ReadAll(res.Body)
108	if err != nil {
109		return ApiResponse{}, err
110	}
111
112	if bot.config.debug {
113		log.Println(string(bytes[:]))
114	}
115
116	var apiResp ApiResponse
117	json.Unmarshal(bytes, &apiResp)
118
119	return apiResp, nil
120}
121
122func (bot *BotApi) getMe() (User, error) {
123	resp, err := bot.makeRequest("getMe", nil)
124	if err != nil {
125		return User{}, err
126	}
127
128	var user User
129	json.Unmarshal(resp.Result, &user)
130
131	if bot.config.debug {
132		log.Printf("getMe: %+v\n", user)
133	}
134
135	return user, nil
136}
137
138func (bot *BotApi) sendMessage(config MessageConfig) (Message, error) {
139	v := url.Values{}
140	v.Add("chat_id", strconv.Itoa(config.ChatId))
141	v.Add("text", config.Text)
142	v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
143	if config.ReplyToMessageId != 0 {
144		v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId))
145	}
146
147	resp, err := bot.makeRequest("sendMessage", v)
148	if err != nil {
149		return Message{}, err
150	}
151
152	var message Message
153	json.Unmarshal(resp.Result, &message)
154
155	if bot.config.debug {
156		log.Printf("sendMessage req : %+v\n", v)
157		log.Printf("sendMessage resp: %+v\n", message)
158	}
159
160	return message, nil
161}
162
163func (bot *BotApi) forwardMessage(config ForwardConfig) (Message, error) {
164	v := url.Values{}
165	v.Add("chat_id", strconv.Itoa(config.ChatId))
166	v.Add("from_chat_id", strconv.Itoa(config.FromChatId))
167	v.Add("message_id", strconv.Itoa(config.MessageId))
168
169	resp, err := bot.makeRequest("forwardMessage", v)
170	if err != nil {
171		return Message{}, err
172	}
173
174	var message Message
175	json.Unmarshal(resp.Result, &message)
176
177	if bot.config.debug {
178		log.Printf("forwardMessage req : %+v\n", v)
179		log.Printf("forwardMessage resp: %+v\n", message)
180	}
181
182	return message, nil
183}
184
185func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) {
186	if config.UseExistingPhoto {
187		v := url.Values{}
188		v.Add("chat_id", strconv.Itoa(config.ChatId))
189		v.Add("photo", config.FileId)
190		if config.Caption != "" {
191			v.Add("caption", config.Caption)
192		}
193		if config.ReplyToMessageId != 0 {
194			v.Add("reply_to_message_id", strconv.Itoa(config.ChatId))
195		}
196		if config.ReplyMarkup != nil {
197			data, err := json.Marshal(config.ReplyMarkup)
198			if err != nil {
199				return Message{}, err
200			}
201
202			v.Add("reply_markup", string(data))
203		}
204
205		resp, err := bot.makeRequest("sendPhoto", v)
206		if err != nil {
207			return Message{}, err
208		}
209
210		var message Message
211		json.Unmarshal(resp.Result, &message)
212
213		if bot.config.debug {
214			log.Printf("sendPhoto req : %+v\n", v)
215			log.Printf("sendPhoto resp: %+v\n", message)
216		}
217
218		return message, nil
219	}
220
221	params := make(map[string]string)
222	params["chat_id"] = strconv.Itoa(config.ChatId)
223	if config.Caption != "" {
224		params["caption"] = config.Caption
225	}
226	if config.ReplyToMessageId != 0 {
227		params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId)
228	}
229	if config.ReplyMarkup != nil {
230		data, err := json.Marshal(config.ReplyMarkup)
231		if err != nil {
232			return Message{}, err
233		}
234
235		params["reply_markup"] = string(data)
236	}
237
238	resp, err := bot.uploadFile("sendPhoto", params, "photo", config.FilePath)
239	if err != nil {
240		return Message{}, err
241	}
242
243	var message Message
244	json.Unmarshal(resp.Result, &message)
245
246	if bot.config.debug {
247		log.Printf("sendPhoto resp: %+v\n", message)
248	}
249
250	return message, nil
251}
252
253func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) {
254	if config.UseExistingAudio {
255		v := url.Values{}
256		v.Add("chat_id", strconv.Itoa(config.ChatId))
257		v.Add("audio", config.FileId)
258		if config.ReplyToMessageId != 0 {
259			v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId))
260		}
261		if config.ReplyMarkup != nil {
262			data, err := json.Marshal(config.ReplyMarkup)
263			if err != nil {
264				return Message{}, err
265			}
266
267			v.Add("reply_markup", string(data))
268		}
269
270		resp, err := bot.makeRequest("sendAudio", v)
271		if err != nil {
272			return Message{}, err
273		}
274
275		var message Message
276		json.Unmarshal(resp.Result, &message)
277
278		if bot.config.debug {
279			log.Printf("sendAudio req : %+v\n", v)
280			log.Printf("sendAudio resp: %+v\n", message)
281		}
282
283		return message, nil
284	}
285
286	params := make(map[string]string)
287
288	params["chat_id"] = strconv.Itoa(config.ChatId)
289	if config.ReplyToMessageId != 0 {
290		params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId)
291	}
292	if config.ReplyMarkup != nil {
293		data, err := json.Marshal(config.ReplyMarkup)
294		if err != nil {
295			return Message{}, err
296		}
297
298		params["reply_markup"] = string(data)
299	}
300
301	resp, err := bot.uploadFile("sendAudio", params, "audio", config.FilePath)
302	if err != nil {
303		return Message{}, err
304	}
305
306	var message Message
307	json.Unmarshal(resp.Result, &message)
308
309	if bot.config.debug {
310		log.Printf("sendAudio resp: %+v\n", message)
311	}
312
313	return message, nil
314}
315
316func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) {
317	if config.UseExistingDocument {
318		v := url.Values{}
319		v.Add("chat_id", strconv.Itoa(config.ChatId))
320		v.Add("document", config.FileId)
321		if config.ReplyToMessageId != 0 {
322			v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId))
323		}
324		if config.ReplyMarkup != nil {
325			data, err := json.Marshal(config.ReplyMarkup)
326			if err != nil {
327				return Message{}, err
328			}
329
330			v.Add("reply_markup", string(data))
331		}
332
333		resp, err := bot.makeRequest("sendDocument", v)
334		if err != nil {
335			return Message{}, err
336		}
337
338		var message Message
339		json.Unmarshal(resp.Result, &message)
340
341		if bot.config.debug {
342			log.Printf("sendDocument req : %+v\n", v)
343			log.Printf("sendDocument resp: %+v\n", message)
344		}
345
346		return message, nil
347	}
348
349	params := make(map[string]string)
350
351	params["chat_id"] = strconv.Itoa(config.ChatId)
352	if config.ReplyToMessageId != 0 {
353		params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId)
354	}
355	if config.ReplyMarkup != nil {
356		data, err := json.Marshal(config.ReplyMarkup)
357		if err != nil {
358			return Message{}, err
359		}
360
361		params["reply_markup"] = string(data)
362	}
363
364	resp, err := bot.uploadFile("sendDocument", params, "document", config.FilePath)
365	if err != nil {
366		return Message{}, err
367	}
368
369	var message Message
370	json.Unmarshal(resp.Result, &message)
371
372	if bot.config.debug {
373		log.Printf("sendDocument resp: %+v\n", message)
374	}
375
376	return message, nil
377}
378
379func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
380	if config.UseExistingSticker {
381		v := url.Values{}
382		v.Add("chat_id", strconv.Itoa(config.ChatId))
383		v.Add("sticker", config.FileId)
384		if config.ReplyToMessageId != 0 {
385			v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId))
386		}
387		if config.ReplyMarkup != nil {
388			data, err := json.Marshal(config.ReplyMarkup)
389			if err != nil {
390				return Message{}, err
391			}
392
393			v.Add("reply_markup", string(data))
394		}
395
396		resp, err := bot.makeRequest("sendSticker", v)
397		if err != nil {
398			return Message{}, err
399		}
400
401		var message Message
402		json.Unmarshal(resp.Result, &message)
403
404		if bot.config.debug {
405			log.Printf("sendSticker req : %+v\n", v)
406			log.Printf("sendSticker resp: %+v\n", message)
407		}
408
409		return message, nil
410	}
411
412	params := make(map[string]string)
413
414	params["chat_id"] = strconv.Itoa(config.ChatId)
415	if config.ReplyToMessageId != 0 {
416		params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId)
417	}
418	if config.ReplyMarkup != nil {
419		data, err := json.Marshal(config.ReplyMarkup)
420		if err != nil {
421			return Message{}, err
422		}
423
424		params["reply_markup"] = string(data)
425	}
426
427	resp, err := bot.uploadFile("sendSticker", params, "sticker", config.FilePath)
428	if err != nil {
429		return Message{}, err
430	}
431
432	var message Message
433	json.Unmarshal(resp.Result, &message)
434
435	if bot.config.debug {
436		log.Printf("sendSticker resp: %+v\n", message)
437	}
438
439	return message, nil
440}
441
442func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
443	if config.UseExistingVideo {
444		v := url.Values{}
445		v.Add("chat_id", strconv.Itoa(config.ChatId))
446		v.Add("video", config.FileId)
447		if config.ReplyToMessageId != 0 {
448			v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId))
449		}
450		if config.ReplyMarkup != nil {
451			data, err := json.Marshal(config.ReplyMarkup)
452			if err != nil {
453				return Message{}, err
454			}
455
456			v.Add("reply_markup", string(data))
457		}
458
459		resp, err := bot.makeRequest("sendVideo", v)
460		if err != nil {
461			return Message{}, err
462		}
463
464		var message Message
465		json.Unmarshal(resp.Result, &message)
466
467		if bot.config.debug {
468			log.Printf("sendVideo req : %+v\n", v)
469			log.Printf("sendVideo resp: %+v\n", message)
470		}
471
472		return message, nil
473	}
474
475	params := make(map[string]string)
476
477	params["chat_id"] = strconv.Itoa(config.ChatId)
478	if config.ReplyToMessageId != 0 {
479		params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId)
480	}
481	if config.ReplyMarkup != nil {
482		data, err := json.Marshal(config.ReplyMarkup)
483		if err != nil {
484			return Message{}, err
485		}
486
487		params["reply_markup"] = string(data)
488	}
489
490	resp, err := bot.uploadFile("sendVideo", params, "video", config.FilePath)
491	if err != nil {
492		return Message{}, err
493	}
494
495	var message Message
496	json.Unmarshal(resp.Result, &message)
497
498	if bot.config.debug {
499		log.Printf("sendVideo resp: %+v\n", message)
500	}
501
502	return message, nil
503}
504
505func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) {
506	v := url.Values{}
507	v.Add("chat_id", strconv.Itoa(config.ChatId))
508	v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
509	v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
510	if config.ReplyToMessageId != 0 {
511		v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId))
512	}
513	if config.ReplyMarkup != nil {
514		data, err := json.Marshal(config.ReplyMarkup)
515		if err != nil {
516			return Message{}, err
517		}
518
519		v.Add("reply_markup", string(data))
520	}
521
522	resp, err := bot.makeRequest("sendLocation", v)
523	if err != nil {
524		return Message{}, err
525	}
526
527	var message Message
528	json.Unmarshal(resp.Result, &message)
529
530	if bot.config.debug {
531		log.Printf("sendLocation req : %+v\n", v)
532		log.Printf("sendLocation resp: %+v\n", message)
533	}
534
535	return message, nil
536}
537
538func (bot *BotApi) sendChatAction(config ChatActionConfig) error {
539	v := url.Values{}
540	v.Add("chat_id", strconv.Itoa(config.ChatId))
541	v.Add("action", config.Action)
542
543	_, err := bot.makeRequest("sendChatAction", v)
544	if err != nil {
545		return err
546	}
547
548	return nil
549}
550
551func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
552	v := url.Values{}
553	v.Add("user_id", strconv.Itoa(config.UserId))
554	if config.Offset != 0 {
555		v.Add("offset", strconv.Itoa(config.Offset))
556	}
557	if config.Limit != 0 {
558		v.Add("limit", strconv.Itoa(config.Limit))
559	}
560
561	resp, err := bot.makeRequest("getUserProfilePhotos", v)
562	if err != nil {
563		return UserProfilePhotos{}, err
564	}
565
566	var profilePhotos UserProfilePhotos
567	json.Unmarshal(resp.Result, &profilePhotos)
568
569	if bot.config.debug {
570		log.Printf("getUserProfilePhotos req : %+v\n", v)
571		log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos)
572	}
573
574	return profilePhotos, nil
575}
576
577func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) {
578	v := url.Values{}
579	if config.Offset > 0 {
580		v.Add("offset", strconv.Itoa(config.Offset))
581	}
582	if config.Limit > 0 {
583		v.Add("limit", strconv.Itoa(config.Limit))
584	}
585	if config.Timeout > 0 {
586		v.Add("timeout", strconv.Itoa(config.Timeout))
587	}
588
589	resp, err := bot.makeRequest("getUpdates", v)
590	if err != nil {
591		return []Update{}, err
592	}
593
594	var updates []Update
595	json.Unmarshal(resp.Result, &updates)
596
597	if bot.config.debug {
598		log.Printf("getUpdates: %+v\n", updates)
599	}
600
601	return updates, nil
602}
603
604func (bot *BotApi) setWebhook(v url.Values) error {
605	_, err := bot.makeRequest("setWebhook", v)
606
607	return err
608}
609
610type UpdateConfig struct {
611	Offset  int
612	Limit   int
613	Timeout int
614}
615
616type MessageConfig struct {
617	ChatId                int
618	Text                  string
619	DisableWebPagePreview bool
620	ReplyToMessageId      int
621}
622
623type ForwardConfig struct {
624	ChatId     int
625	FromChatId int
626	MessageId  int
627}
628
629type PhotoConfig struct {
630	ChatId           int
631	Caption          string
632	ReplyToMessageId int
633	ReplyMarkup      interface{}
634	UseExistingPhoto bool
635	FilePath         string
636	FileId           string
637}
638
639type AudioConfig struct {
640	ChatId           int
641	ReplyToMessageId int
642	ReplyMarkup      interface{}
643	UseExistingAudio bool
644	FilePath         string
645	FileId           string
646}
647
648type DocumentConfig struct {
649	ChatId              int
650	ReplyToMessageId    int
651	ReplyMarkup         interface{}
652	UseExistingDocument bool
653	FilePath            string
654	FileId              string
655}
656
657type StickerConfig struct {
658	ChatId             int
659	ReplyToMessageId   int
660	ReplyMarkup        interface{}
661	UseExistingSticker bool
662	FilePath           string
663	FileId             string
664}
665
666type VideoConfig struct {
667	ChatId           int
668	ReplyToMessageId int
669	ReplyMarkup      interface{}
670	UseExistingVideo bool
671	FilePath         string
672	FileId           string
673}
674
675type LocationConfig struct {
676	ChatId           int
677	Latitude         float64
678	Longitude        float64
679	ReplyToMessageId int
680	ReplyMarkup      interface{}
681}
682
683type ChatActionConfig struct {
684	ChatId int
685	Action string
686}
687
688type UserProfilePhotosConfig struct {
689	UserId int
690	Offset int
691	Limit  int
692}
693
694func NewMessage(chatId int, text string) MessageConfig {
695	return MessageConfig{
696		ChatId: chatId,
697		Text:   text,
698		DisableWebPagePreview: false,
699		ReplyToMessageId:      0,
700	}
701}
702
703func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig {
704	return ForwardConfig{
705		ChatId:     chatId,
706		FromChatId: fromChatId,
707		MessageId:  messageId,
708	}
709}
710
711func NewPhotoUpload(chatId int, filename string) PhotoConfig {
712	return PhotoConfig{
713		ChatId:           chatId,
714		UseExistingPhoto: false,
715		FilePath:         filename,
716	}
717}
718
719func NewPhotoShare(chatId int, fileId string) PhotoConfig {
720	return PhotoConfig{
721		ChatId:           chatId,
722		UseExistingPhoto: true,
723		FileId:           fileId,
724	}
725}
726
727func NewAudioUpload(chatId int, filename string) AudioConfig {
728	return AudioConfig{
729		ChatId:           chatId,
730		UseExistingAudio: false,
731		FilePath:         filename,
732	}
733}
734
735func NewAudioShare(chatId int, fileId string) AudioConfig {
736	return AudioConfig{
737		ChatId:           chatId,
738		UseExistingAudio: true,
739		FileId:           fileId,
740	}
741}
742
743func NewDocumentUpload(chatId int, filename string) DocumentConfig {
744	return DocumentConfig{
745		ChatId:              chatId,
746		UseExistingDocument: false,
747		FilePath:            filename,
748	}
749}
750
751func NewDocumentShare(chatId int, fileId string) DocumentConfig {
752	return DocumentConfig{
753		ChatId:              chatId,
754		UseExistingDocument: true,
755		FileId:              fileId,
756	}
757}
758
759func NewStickerUpload(chatId int, filename string) StickerConfig {
760	return StickerConfig{
761		ChatId:             chatId,
762		UseExistingSticker: false,
763		FilePath:           filename,
764	}
765}
766
767func NewStickerShare(chatId int, fileId string) StickerConfig {
768	return StickerConfig{
769		ChatId:             chatId,
770		UseExistingSticker: true,
771		FileId:             fileId,
772	}
773}
774
775func NewVideoUpload(chatId int, filename string) VideoConfig {
776	return VideoConfig{
777		ChatId:           chatId,
778		UseExistingVideo: false,
779		FilePath:         filename,
780	}
781}
782
783func NewVideoShare(chatId int, fileId string) VideoConfig {
784	return VideoConfig{
785		ChatId:           chatId,
786		UseExistingVideo: true,
787		FileId:           fileId,
788	}
789}
790
791func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig {
792	return LocationConfig{
793		ChatId:           chatId,
794		Latitude:         latitude,
795		Longitude:        longitude,
796		ReplyToMessageId: 0,
797		ReplyMarkup:      nil,
798	}
799}
800
801func NewChatAction(chatId int, action string) ChatActionConfig {
802	return ChatActionConfig{
803		ChatId: chatId,
804		Action: action,
805	}
806}
807
808func NewUserProfilePhotos(userId int) UserProfilePhotosConfig {
809	return UserProfilePhotosConfig{
810		UserId: userId,
811		Offset: 0,
812		Limit:  0,
813	}
814}
815
816func NewUpdate(offset int) UpdateConfig {
817	return UpdateConfig{
818		Offset:  offset,
819		Limit:   0,
820		Timeout: 0,
821	}
822}