diff options
-rw-r--r-- | api.go | 5 | ||||
-rw-r--r-- | client.go | 14 | ||||
-rw-r--r-- | examples/example.go | 31 | ||||
-rw-r--r-- | examples/example.jpg | bin | 0 -> 204261 bytes | |||
-rw-r--r-- | messages.go | 4 | ||||
-rw-r--r-- | models.go | 11 | ||||
-rw-r--r-- | uploads.go | 49 |
7 files changed, 89 insertions, 25 deletions
@@ -28,8 +28,9 @@ type Api struct { // New TamTam Api object func New(key string) *Api { + timeout := 30 u, _ := url.Parse("https://botapi.tamtam.chat/") - cl := newClient(key, "0.1.8", u) + cl := newClient(key, "0.1.8", u, &http.Client{Timeout: time.Duration(timeout) * time.Second}) return &Api{ Bots: newBots(cl), Chats: newChats(cl), @@ -38,7 +39,7 @@ func New(key string) *Api { Subscriptions: newSubscriptions(cl), client: cl, updates: make(chan UpdateInterface), - timeout: 30, + timeout: timeout, pause: 1, } } @@ -10,13 +10,14 @@ import ( ) type client struct { - key string - version string - url *url.URL + key string + version string + url *url.URL + httpClient *http.Client } -func newClient(key string, version string, url *url.URL) *client { - return &client{key: key, version: version, url: url} +func newClient(key string, version string, url *url.URL, httpClient *http.Client) *client { + return &client{key: key, version: version, url: url, httpClient: httpClient} } func (cl *client) request(method, path string, query url.Values, body interface{}) (io.ReadCloser, error) { @@ -28,7 +29,6 @@ func (cl *client) request(method, path string, query url.Values, body interface{ } func (cl *client) requestReader(method, path string, query url.Values, body io.Reader) (io.ReadCloser, error) { - c := http.DefaultClient u := *cl.url u.Path = path query.Set("access_token", cl.key) @@ -38,7 +38,7 @@ func (cl *client) requestReader(method, path string, query url.Values, body io.R if err != nil { return nil, err } - resp, err := c.Do(req) + resp, err := cl.httpClient.Do(req) if err != nil { return nil, err } diff --git a/examples/example.go b/examples/example.go index b4e84ac..8effc67 100644 --- a/examples/example.go +++ b/examples/example.go @@ -1,5 +1,3 @@ -// +build ignore - package main import ( @@ -32,6 +30,9 @@ func main() { AddLink("Библиотека", tamtam.POSITIVE, "https://github.com/neonxp/tamtam"). AddCallback("Колбек 1", tamtam.NEGATIVE, "callback_1"). AddCallback("Колбек 2", tamtam.NEGATIVE, "callback_2") + keyboard. + AddRow(). + AddCallback("Картинка", tamtam.POSITIVE, "picture") // Отправка сообщения с клавиатурой res, err := api.Messages.SendMessage(0, upd.Message.Sender.UserId, &tamtam.NewMessageBody{ @@ -42,10 +43,30 @@ func main() { }) log.Printf("Answer: %#v %#v", res, err) case *tamtam.MessageCallbackUpdate: - res, err := api.Messages.SendMessage(0, upd.Callback.User.UserId, &tamtam.NewMessageBody{ - Text: "Callback: " + upd.Callback.Payload, - }) + // Ответ на коллбек + attachments := make([]interface{}, 0) + if upd.Callback.Payload == "picture" { + photo, err := api.Uploads.UploadPhoto("./examples/example.jpg") + if err != nil { + log.Fatal(err) + } + attachments = append(attachments, tamtam.NewPhotoAttachmentRequest(tamtam.PhotoAttachmentRequestPayload{Photos: photo.Photos})) + } + res, err := api.Messages.AnswerOnCallback( + upd.Callback.CallbackID, + &tamtam.CallbackAnswer{ + UserId: upd.Callback.User.UserId, + Message: &tamtam.NewMessageBody{ + Text: "OK!", + }, + Notification: "Callback is ok", + }) log.Printf("Answer: %#v %#v", res, err) + res2, err := api.Messages.SendMessage(0, upd.Callback.User.UserId, &tamtam.NewMessageBody{ + Text: upd.Callback.Payload + " at " + upd.GetUpdateTime().String(), + Attachments: attachments, + }) + log.Printf("Answer: %#v %#v", res2, err) default: log.Printf("Unknown type: %#v", upd) } diff --git a/examples/example.jpg b/examples/example.jpg Binary files differnew file mode 100644 index 0000000..c167a3e --- /dev/null +++ b/examples/example.jpg diff --git a/messages.go b/messages.go index 79c9e78..5131479 100644 --- a/messages.go +++ b/messages.go @@ -106,10 +106,10 @@ func (a *messages) DeleteMessage(messageID int) (*SimpleQueryResult, error) { } //AnswerOnCallback should be called to send an answer after a user has clicked the button. The answer may be an updated message or/and a one-time user notification. -func (a *messages) AnswerOnCallback(callbackID int, callback *CallbackAnswer) (*SimpleQueryResult, error) { +func (a *messages) AnswerOnCallback(callbackID string, callback *CallbackAnswer) (*SimpleQueryResult, error) { result := new(SimpleQueryResult) values := url.Values{} - values.Set("callback_id", strconv.Itoa(int(callbackID))) + values.Set("callback_id", callbackID) body, err := a.client.request(http.MethodPost, "answers", values, callback) if err != nil { return result, err @@ -434,9 +434,9 @@ type PhotoAttachmentRequestAllOf struct { // Request to attach image. All fields are mutually exclusive type PhotoAttachmentRequestPayload struct { - Url string `json:"url,omitempty"` // Any external image URL you want to attach - Token string `json:"token,omitempty"` // Token of any existing attachment - Photos *map[string]PhotoToken `json:"photos,omitempty"` // Tokens were obtained after uploading images + Url string `json:"url,omitempty"` // Any external image URL you want to attach + Token string `json:"token,omitempty"` // Token of any existing attachment + Photos map[string]PhotoToken `json:"photos,omitempty"` // Tokens were obtained after uploading images } type PhotoToken struct { @@ -559,7 +559,8 @@ const ( // This is information you will receive as soon as audio/video is uploaded type UploadedInfo struct { - Token string `json:"token,omitempty"` // Token is unique uploaded media identfier + FileID int `json:"file_id,omitempty"` + Token string `json:"token,omitempty"` // Token is unique uploaded media identfier } type User struct { @@ -606,7 +607,7 @@ func (u Update) GetUpdateType() UpdateType { } func (u Update) GetUpdateTime() time.Time { - return time.Unix(int64(u.Timestamp), 0) + return time.Unix(int64(u.Timestamp/1000), 0) } type UpdateInterface interface { @@ -37,7 +37,7 @@ func (a *uploads) GetUploadURL(uploadType UploadType) (*UploadEndpoint, error) { } //UploadMedia uploads file to TamTam server -func (a *uploads) UploadMedia(uploadType UploadType, filename string) (*UploadedInfo, error) { +func (a *uploads) UploadMedia(endpoint *UploadEndpoint, filename string) (*UploadedInfo, error) { bodyBuf := &bytes.Buffer{} bodyWriter := multipart.NewWriter(bodyBuf) @@ -63,14 +63,55 @@ func (a *uploads) UploadMedia(uploadType UploadType, filename string) (*Uploaded if err := bodyWriter.Close(); err != nil { return nil, err } + contentType := bodyWriter.FormDataContentType() + resp, err := http.Post(endpoint.Url, contentType, bodyBuf) + if err != nil { + return nil, err + } + defer func() { + if err := resp.Body.Close(); err != nil { + log.Println(err) + } + }() + result := new(UploadedInfo) + return result, json.NewDecoder(resp.Body).Decode(result) +} + +//UploadPhoto uploads photos to TamTam server +func (a *uploads) UploadPhoto(filename string) (*PhotoTokens, error) { + bodyBuf := &bytes.Buffer{} + bodyWriter := multipart.NewWriter(bodyBuf) - target, err := a.GetUploadURL(uploadType) + fileWriter, err := bodyWriter.CreateFormFile("data", filename) + if err != nil { + return nil, err + } + + fh, err := os.Open(filename) + if err != nil { + return nil, err + } + defer func() { + if err := fh.Close(); err != nil { + log.Println(err) + } + }() + _, err = io.Copy(fileWriter, fh) + if err != nil { + return nil, err + } + + if err := bodyWriter.Close(); err != nil { + return nil, err + } + + endpoint, err := a.GetUploadURL(PHOTO) if err != nil { return nil, err } contentType := bodyWriter.FormDataContentType() - resp, err := http.Post(target.Url, contentType, bodyBuf) + resp, err := http.Post(endpoint.Url, contentType, bodyBuf) if err != nil { return nil, err } @@ -79,6 +120,6 @@ func (a *uploads) UploadMedia(uploadType UploadType, filename string) (*Uploaded log.Println(err) } }() - result := new(UploadedInfo) + result := new(PhotoTokens) return result, json.NewDecoder(resp.Body).Decode(result) } |