Sending photos, API improvements

pull/3/head
Ilya Kowalewski 9 years ago
parent 418934be9c
commit 6a4863ece8

117
api.go

@ -1,15 +1,20 @@
package telebot
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
)
func performApiCall(method string, token string, params url.Values) ([]byte, error) {
func api_GET(method string, token string, params url.Values) ([]byte, error) {
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s?%s",
token, method, params.Encode())
@ -27,8 +32,58 @@ func performApiCall(method string, token string, params url.Values) ([]byte, err
return json, nil
}
func api_POST(method, token, name, path string, params url.Values) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return []byte{}, err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(name, filepath.Base(path))
if err != nil {
return []byte{}, err
}
if _, err = io.Copy(part, file); err != nil {
return []byte{}, err
}
for field, values := range params {
if len(values) > 0 {
writer.WriteField(field, values[0])
}
}
if err = writer.Close(); err != nil {
return []byte{}, err
}
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", token, method)
req, err := http.NewRequest("POST", url, body)
if err != nil {
return []byte{}, err
}
req.Header.Add("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return []byte{}, err
}
json, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, err
}
return json, nil
}
func api_getMe(token string) (User, error) {
me_json, err := performApiCall("getMe", token, url.Values{})
me_json, err := api_GET("getMe", token, url.Values{})
if err != nil {
return User{}, err
}
@ -53,8 +108,8 @@ func api_getMe(token string) (User, error) {
func api_getUpdates(token string, offset int, updates chan<- Update) error {
params := url.Values{}
params.Set("offset", strconv.FormatInt(int64(offset), 10))
updates_json, err := performApiCall("getUpdates", token, params)
params.Set("offset", strconv.Itoa(offset))
updates_json, err := api_GET("getUpdates", token, params)
if err != nil {
return err
}
@ -83,9 +138,9 @@ func api_getUpdates(token string, offset int, updates chan<- Update) error {
func api_sendMessage(token string, recipient User, text string) error {
params := url.Values{}
params.Set("chat_id", strconv.FormatInt(int64(recipient.Id), 10))
params.Set("chat_id", strconv.Itoa(recipient.Id))
params.Set("text", text)
response_json, err := performApiCall("sendMessage", token, params)
response_json, err := api_GET("sendMessage", token, params)
if err != nil {
return err
}
@ -109,18 +164,55 @@ func api_sendMessage(token string, recipient User, text string) error {
func api_forwardMessage(token string, recipient User, message Message) error {
params := url.Values{}
params.Set("chat_id", strconv.FormatInt(int64(recipient.Id), 10))
params.Set("from_chat_id",
strconv.FormatInt(int64(message.Origin().Id), 10))
params.Set("message_id", strconv.FormatInt(int64(message.Id), 10))
params.Set("chat_id", strconv.Itoa(recipient.Id))
params.Set("from_chat_id", strconv.Itoa(message.Origin().Id))
params.Set("message_id", strconv.Itoa(message.Id))
response_json, err := api_GET("forwardMessage", token, params)
if err != nil {
return err
}
var response_recieved struct {
Ok bool
Description string
}
err = json.Unmarshal(response_json, &response_recieved)
if err != nil {
return err
}
if !response_recieved.Ok {
return SendError{response_recieved.Description}
}
return nil
}
func api_sendPhoto(token string, recipient User, photo *Photo) error {
params := url.Values{}
params.Set("chat_id", strconv.Itoa(recipient.Id))
params.Set("caption", photo.Caption)
var response_json []byte
var err error
if photo.Exists() {
params.Set("photo", photo.FileId)
response_json, err = api_GET("sendPhoto", token, params)
} else {
response_json, err = api_POST("sendPhoto", token, "photo",
photo.filename, params)
}
response_json, err := performApiCall("forwardMessage", token, params)
if err != nil {
return err
}
var response_recieved struct {
Ok bool
Result Message
Description string
}
@ -133,5 +225,8 @@ func api_forwardMessage(token string, recipient User, message Message) error {
return SendError{response_recieved.Description}
}
thumbnails := &response_recieved.Result.Photo
photo.File = (*thumbnails)[len(*thumbnails)-1].File
return nil
}

@ -47,3 +47,8 @@ func (b *Bot) SendMessage(recipient User, message string) error {
func (b *Bot) ForwardMessage(recipient User, message Message) error {
return api_forwardMessage(b.Token, recipient, message)
}
// SendPhoto sends a photo object to recipient.
func (b *Bot) SendPhoto(recipient User, photo *Photo) error {
return api_sendPhoto(b.Token, recipient, photo)
}

@ -17,6 +17,10 @@ type SendError struct {
Payload string
}
type FileError struct {
Payload string
}
func (e AuthError) Error() string {
return "AuthError: " + e.Payload
}
@ -28,3 +32,7 @@ func (e FetchError) Error() string {
func (e SendError) Error() string {
return "SendError: " + e.Payload
}
func (e FileError) Error() string {
return "FileError: " + e.Payload
}

@ -27,6 +27,11 @@
//
package telebot
import (
"fmt"
"os"
)
// Create does try to build a Bot with token `token`, which
// is a secret API key assigned to particular bot.
func Create(token string) (Bot, error) {
@ -40,3 +45,18 @@ func Create(token string) (Bot, error) {
Identity: user,
}, nil
}
// NewFile attempts to create a File object, leading to a real
// file on the file system, that could be uploaded later.
//
// Notice that NewFile doesn't upload file, but only creates
// a descriptor for it.
func NewFile(path string) (File, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return File{}, FileError{
fmt.Sprintf("'%s' does not exist!", path),
}
}
return File{filename: path}, nil
}

@ -17,12 +17,23 @@ type Update struct {
Payload Message `json:"message"`
}
// File object represents any sort of file. Since you would
// only deal with specific files in the wild, this structure
// doesn't make any sense in specific application.
// File object represents any sort of file.
type File struct {
FileId string `json:"file_id"`
FileSize int `json:"file_size"`
// Local absolute path to file on file system. Valid only for
// new files, meant to be uploaded soon.
filename string
}
// Exists says whether file presents on Telegram servers or not.
func (f File) Exists() bool {
if f.filename == "" {
return true
}
return false
}
// Thumbnail object represents a image/sticker of particular size.
@ -33,6 +44,13 @@ type Thumbnail struct {
Height int `json:"height"`
}
// Photo object represents a photo with caption.
type Photo struct {
Thumbnail
Caption string
}
// Audio object represents an audio file (voice note).
type Audio struct {
File

Loading…
Cancel
Save