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}