all repos — telegram-bot-api @ 059baffbfbf2683405ac97a06a3592a203ed5a57

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) sendLocation(config LocationConfig) (Message, error) {
254	v := url.Values{}
255	v.Add("chat_id", strconv.Itoa(config.ChatId))
256	v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
257	v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
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("sendLocation", 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("sendLocation req : %+v\n", v)
280		log.Printf("sendLocation resp: %+v\n", message)
281	}
282
283	return message, nil
284}
285
286func (bot *BotApi) sendChatAction(config ChatActionConfig) error {
287	v := url.Values{}
288	v.Add("chat_id", strconv.Itoa(config.ChatId))
289	v.Add("action", config.Action)
290
291	_, err := bot.makeRequest("sendChatAction", v)
292	if err != nil {
293		return err
294	}
295
296	return nil
297}
298
299func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
300	v := url.Values{}
301	v.Add("user_id", strconv.Itoa(config.UserId))
302	if config.Offset != 0 {
303		v.Add("offset", strconv.Itoa(config.Offset))
304	}
305	if config.Limit != 0 {
306		v.Add("limit", strconv.Itoa(config.Limit))
307	}
308
309	resp, err := bot.makeRequest("getUserProfilePhotos", v)
310	if err != nil {
311		return UserProfilePhotos{}, err
312	}
313
314	var profilePhotos UserProfilePhotos
315	json.Unmarshal(resp.Result, &profilePhotos)
316
317	if bot.config.debug {
318		log.Printf("getUserProfilePhotos req : %+v\n", v)
319		log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos)
320	}
321
322	return profilePhotos, nil
323}
324
325func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) {
326	v := url.Values{}
327	if config.Offset > 0 {
328		v.Add("offset", strconv.Itoa(config.Offset))
329	}
330	if config.Limit > 0 {
331		v.Add("limit", strconv.Itoa(config.Limit))
332	}
333	if config.Timeout > 0 {
334		v.Add("timeout", strconv.Itoa(config.Timeout))
335	}
336
337	resp, err := bot.makeRequest("getUpdates", v)
338	if err != nil {
339		return []Update{}, err
340	}
341
342	var updates []Update
343	json.Unmarshal(resp.Result, &updates)
344
345	if bot.config.debug {
346		log.Printf("getUpdates: %+v\n", updates)
347	}
348
349	return updates, nil
350}
351
352func (bot *BotApi) setWebhook(v url.Values) error {
353	_, err := bot.makeRequest("setWebhook", v)
354
355	return err
356}
357
358type UpdateConfig struct {
359	Offset  int
360	Limit   int
361	Timeout int
362}
363
364type MessageConfig struct {
365	ChatId                int
366	Text                  string
367	DisableWebPagePreview bool
368	ReplyToMessageId      int
369}
370
371type ForwardConfig struct {
372	ChatId     int
373	FromChatId int
374	MessageId  int
375}
376
377type PhotoConfig struct {
378	ChatId           int
379	Caption          string
380	ReplyToMessageId int
381	ReplyMarkup      interface{}
382	UseExistingPhoto bool
383	FilePath         string
384	FileId           string
385}
386
387type LocationConfig struct {
388	ChatId           int
389	Latitude         float64
390	Longitude        float64
391	ReplyToMessageId int
392	ReplyMarkup      interface{}
393}
394
395type ChatActionConfig struct {
396	ChatId int
397	Action string
398}
399
400type UserProfilePhotosConfig struct {
401	UserId int
402	Offset int
403	Limit  int
404}
405
406func NewMessage(chatId int, text string) MessageConfig {
407	return MessageConfig{
408		ChatId: chatId,
409		Text:   text,
410		DisableWebPagePreview: false,
411		ReplyToMessageId:      0,
412	}
413}
414
415func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig {
416	return ForwardConfig{
417		ChatId:     chatId,
418		FromChatId: fromChatId,
419		MessageId:  messageId,
420	}
421}
422
423func NewPhotoUpload(chatId int, filename string) PhotoConfig {
424	return PhotoConfig{
425		ChatId:           chatId,
426		UseExistingPhoto: false,
427		FilePath:         filename,
428	}
429}
430
431func NewPhotoShare(chatId int, fileId string) PhotoConfig {
432	return PhotoConfig{
433		ChatId:           chatId,
434		UseExistingPhoto: true,
435		FileId:           fileId,
436	}
437}
438
439func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig {
440	return LocationConfig{
441		ChatId:           chatId,
442		Latitude:         latitude,
443		Longitude:        longitude,
444		ReplyToMessageId: 0,
445		ReplyMarkup:      nil,
446	}
447}
448
449func NewChatAction(chatId int, action string) ChatActionConfig {
450	return ChatActionConfig{
451		ChatId: chatId,
452		Action: action,
453	}
454}
455
456func NewUserProfilePhotos(userId int) UserProfilePhotosConfig {
457	return UserProfilePhotosConfig{
458		UserId: userId,
459		Offset: 0,
460		Limit:  0,
461	}
462}
463
464func NewUpdate(offset int) UpdateConfig {
465	return UpdateConfig{
466		Offset:  offset,
467		Limit:   0,
468		Timeout: 0,
469	}
470}