all repos — telegram-bot-api @ 224e585bd97ba06daa9ab566d6b277385b1bd3ae

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) sendDocument(config DocumentConfig) (Message, error) {
254	if config.UseExitingDocument {
255		v := url.Values{}
256		v.Add("chat_id", strconv.Itoa(config.ChatId))
257		v.Add("document", 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("sendDocument", 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("sendDocument req : %+v\n", v)
280			log.Printf("sendDocument 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("sendDocument", params, "document", 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("sendDocument resp: %+v\n", message)
311	}
312
313	return message, nil
314}
315
316func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
317	if config.UseExistingSticker {
318		v := url.Values{}
319		v.Add("chat_id", strconv.Itoa(config.ChatId))
320		v.Add("sticker", 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("sendSticker", 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("sendSticker req : %+v\n", v)
343			log.Printf("sendSticker 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("sendSticker", params, "sticker", 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("sendSticker resp: %+v\n", message)
374	}
375
376	return message, nil
377}
378
379func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
380	if config.UseExistingVideo {
381		v := url.Values{}
382		v.Add("chat_id", strconv.Itoa(config.ChatId))
383		v.Add("video", 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("sendVideo", 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("sendVideo req : %+v\n", v)
406			log.Printf("sendVideo 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("sendVideo", params, "video", 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("sendVideo resp: %+v\n", message)
437	}
438
439	return message, nil
440}
441
442func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) {
443	v := url.Values{}
444	v.Add("chat_id", strconv.Itoa(config.ChatId))
445	v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
446	v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
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("sendLocation", 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("sendLocation req : %+v\n", v)
469		log.Printf("sendLocation resp: %+v\n", message)
470	}
471
472	return message, nil
473}
474
475func (bot *BotApi) sendChatAction(config ChatActionConfig) error {
476	v := url.Values{}
477	v.Add("chat_id", strconv.Itoa(config.ChatId))
478	v.Add("action", config.Action)
479
480	_, err := bot.makeRequest("sendChatAction", v)
481	if err != nil {
482		return err
483	}
484
485	return nil
486}
487
488func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
489	v := url.Values{}
490	v.Add("user_id", strconv.Itoa(config.UserId))
491	if config.Offset != 0 {
492		v.Add("offset", strconv.Itoa(config.Offset))
493	}
494	if config.Limit != 0 {
495		v.Add("limit", strconv.Itoa(config.Limit))
496	}
497
498	resp, err := bot.makeRequest("getUserProfilePhotos", v)
499	if err != nil {
500		return UserProfilePhotos{}, err
501	}
502
503	var profilePhotos UserProfilePhotos
504	json.Unmarshal(resp.Result, &profilePhotos)
505
506	if bot.config.debug {
507		log.Printf("getUserProfilePhotos req : %+v\n", v)
508		log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos)
509	}
510
511	return profilePhotos, nil
512}
513
514func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) {
515	v := url.Values{}
516	if config.Offset > 0 {
517		v.Add("offset", strconv.Itoa(config.Offset))
518	}
519	if config.Limit > 0 {
520		v.Add("limit", strconv.Itoa(config.Limit))
521	}
522	if config.Timeout > 0 {
523		v.Add("timeout", strconv.Itoa(config.Timeout))
524	}
525
526	resp, err := bot.makeRequest("getUpdates", v)
527	if err != nil {
528		return []Update{}, err
529	}
530
531	var updates []Update
532	json.Unmarshal(resp.Result, &updates)
533
534	if bot.config.debug {
535		log.Printf("getUpdates: %+v\n", updates)
536	}
537
538	return updates, nil
539}
540
541func (bot *BotApi) setWebhook(v url.Values) error {
542	_, err := bot.makeRequest("setWebhook", v)
543
544	return err
545}
546
547type UpdateConfig struct {
548	Offset  int
549	Limit   int
550	Timeout int
551}
552
553type MessageConfig struct {
554	ChatId                int
555	Text                  string
556	DisableWebPagePreview bool
557	ReplyToMessageId      int
558}
559
560type ForwardConfig struct {
561	ChatId     int
562	FromChatId int
563	MessageId  int
564}
565
566type PhotoConfig struct {
567	ChatId           int
568	Caption          string
569	ReplyToMessageId int
570	ReplyMarkup      interface{}
571	UseExistingPhoto bool
572	FilePath         string
573	FileId           string
574}
575
576type DocumentConfig struct {
577	ChatId             int
578	ReplyToMessageId   int
579	ReplyMarkup        interface{}
580	UseExitingDocument bool
581	FilePath           string
582	FileId             string
583}
584
585type StickerConfig struct {
586	ChatId             int
587	ReplyToMessageId   int
588	ReplyMarkup        interface{}
589	UseExistingSticker bool
590	FilePath           string
591	FileId             string
592}
593
594type VideoConfig struct {
595	ChatId           int
596	ReplyToMessageId int
597	ReplyMarkup      interface{}
598	UseExistingVideo bool
599	FilePath         string
600	FileId           string
601}
602
603type LocationConfig struct {
604	ChatId           int
605	Latitude         float64
606	Longitude        float64
607	ReplyToMessageId int
608	ReplyMarkup      interface{}
609}
610
611type ChatActionConfig struct {
612	ChatId int
613	Action string
614}
615
616type UserProfilePhotosConfig struct {
617	UserId int
618	Offset int
619	Limit  int
620}
621
622func NewMessage(chatId int, text string) MessageConfig {
623	return MessageConfig{
624		ChatId: chatId,
625		Text:   text,
626		DisableWebPagePreview: false,
627		ReplyToMessageId:      0,
628	}
629}
630
631func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig {
632	return ForwardConfig{
633		ChatId:     chatId,
634		FromChatId: fromChatId,
635		MessageId:  messageId,
636	}
637}
638
639func NewPhotoUpload(chatId int, filename string) PhotoConfig {
640	return PhotoConfig{
641		ChatId:           chatId,
642		UseExistingPhoto: false,
643		FilePath:         filename,
644	}
645}
646
647func NewPhotoShare(chatId int, fileId string) PhotoConfig {
648	return PhotoConfig{
649		ChatId:           chatId,
650		UseExistingPhoto: true,
651		FileId:           fileId,
652	}
653}
654
655func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig {
656	return LocationConfig{
657		ChatId:           chatId,
658		Latitude:         latitude,
659		Longitude:        longitude,
660		ReplyToMessageId: 0,
661		ReplyMarkup:      nil,
662	}
663}
664
665func NewChatAction(chatId int, action string) ChatActionConfig {
666	return ChatActionConfig{
667		ChatId: chatId,
668		Action: action,
669	}
670}
671
672func NewUserProfilePhotos(userId int) UserProfilePhotosConfig {
673	return UserProfilePhotosConfig{
674		UserId: userId,
675		Offset: 0,
676		Limit:  0,
677	}
678}
679
680func NewUpdate(offset int) UpdateConfig {
681	return UpdateConfig{
682		Offset:  offset,
683		Limit:   0,
684		Timeout: 0,
685	}
686}