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}