telebot/bot.go

452 lines
10 KiB
Go
Raw Normal View History

package telebot
import (
2015-07-03 18:54:40 +00:00
"encoding/json"
"fmt"
2015-11-16 10:22:37 +00:00
"log"
2015-07-03 18:54:40 +00:00
"net/url"
"strconv"
"time"
)
// Bot represents a separate Telegram bot instance.
type Bot struct {
Token string
// Bot as `User` on API level.
Identity User
}
2015-07-03 18:54:40 +00:00
// NewBot does try to build a Bot with token `token`, which
// is a secret API key assigned to particular bot.
func NewBot(token string) (*Bot, error) {
user, err := getMe(token)
if err != nil {
return nil, err
}
return &Bot{
Token: token,
Identity: user,
}, nil
}
// Listen periodically looks for updates and delivers new messages
2015-11-16 10:22:37 +00:00
// to the subscription channel.
func (b *Bot) Listen(subscription chan<- Message, timeout time.Duration) {
go func() {
latestUpdate := 0
for {
2015-11-16 10:22:37 +00:00
updates, err := getUpdates(b.Token,
latestUpdate+1,
int(timeout/time.Second),
)
if err != nil {
log.Println("failed to get updates:", err)
continue
}
for _, update := range updates {
latestUpdate = update.ID
subscription <- update.Payload
}
}
}()
}
2015-06-26 16:12:54 +00:00
2015-07-02 11:04:45 +00:00
// SendMessage sends a text message to recipient.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendMessage(recipient Recipient, message string, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
params.Set("text", message)
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
responseJSON, err := sendCommand("sendMessage", b.Token, params)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
return nil
2015-06-26 16:12:54 +00:00
}
2015-07-02 09:05:50 +00:00
2015-07-02 11:04:45 +00:00
// ForwardMessage forwards a message to recipient.
2015-11-16 10:22:37 +00:00
func (b *Bot) ForwardMessage(recipient Recipient, message Message) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
params.Set("from_chat_id", strconv.Itoa(message.Origin().ID))
params.Set("message_id", strconv.Itoa(message.ID))
2015-07-03 18:54:40 +00:00
2015-07-06 13:52:50 +00:00
responseJSON, err := sendCommand("forwardMessage", b.Token, params)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
return nil
2015-07-02 09:05:50 +00:00
}
2015-07-02 18:39:39 +00:00
// SendPhoto sends a photo object to recipient.
2015-07-03 12:27:18 +00:00
//
// On success, photo object would be aliased to its copy on
// the Telegram servers, so sending the same photo object
// again, won't issue a new upload, but would make a use
// of existing file on Telegram servers.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendPhoto(recipient Recipient, photo *Photo, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
params.Set("caption", photo.Caption)
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
var responseJSON []byte
2015-07-03 18:54:40 +00:00
var err error
if photo.Exists() {
params.Set("photo", photo.FileID)
2015-07-06 13:52:50 +00:00
responseJSON, err = sendCommand("sendPhoto", b.Token, params)
2015-07-03 18:54:40 +00:00
} else {
2015-07-06 13:52:50 +00:00
responseJSON, err = sendFile("sendPhoto", b.Token, "photo",
2015-07-03 18:54:40 +00:00
photo.filename, params)
}
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Result Message
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
2015-07-06 13:52:50 +00:00
thumbnails := &responseRecieved.Result.Photo
2015-07-06 16:58:54 +00:00
filename := photo.filename
2015-07-03 18:54:40 +00:00
photo.File = (*thumbnails)[len(*thumbnails)-1].File
2015-07-06 16:58:54 +00:00
photo.filename = filename
2015-07-03 18:54:40 +00:00
return nil
2015-07-02 18:39:39 +00:00
}
2015-07-03 12:27:18 +00:00
// SendAudio sends an audio object to recipient.
2015-07-03 12:27:18 +00:00
//
// On success, audio object would be aliased to its copy on
// the Telegram servers, so sending the same audio object
// again, won't issue a new upload, but would make a use
// of existing file on Telegram servers.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendAudio(recipient Recipient, audio *Audio, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
var responseJSON []byte
2015-07-03 18:54:40 +00:00
var err error
if audio.Exists() {
params.Set("audio", audio.FileID)
2015-07-06 13:52:50 +00:00
responseJSON, err = sendCommand("sendAudio", b.Token, params)
2015-07-03 18:54:40 +00:00
} else {
2015-07-06 13:52:50 +00:00
responseJSON, err = sendFile("sendAudio", b.Token, "audio",
2015-07-03 18:54:40 +00:00
audio.filename, params)
}
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Result Message
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
2015-07-06 16:58:54 +00:00
filename := audio.filename
2015-07-06 13:52:50 +00:00
*audio = responseRecieved.Result.Audio
2015-07-06 16:58:54 +00:00
audio.filename = filename
2015-07-03 18:54:40 +00:00
return nil
2015-07-03 12:27:18 +00:00
}
// SendDocument sends a general document object to recipient.
//
// On success, document object would be aliased to its copy on
// the Telegram servers, so sending the same document object
// again, won't issue a new upload, but would make a use
// of existing file on Telegram servers.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendDocument(recipient Recipient, doc *Document, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
var responseJSON []byte
2015-07-03 18:54:40 +00:00
var err error
if doc.Exists() {
params.Set("document", doc.FileID)
2015-07-06 13:52:50 +00:00
responseJSON, err = sendCommand("sendDocument", b.Token, params)
2015-07-03 18:54:40 +00:00
} else {
2015-07-06 13:52:50 +00:00
responseJSON, err = sendFile("sendDocument", b.Token, "document",
2015-07-03 18:54:40 +00:00
doc.filename, params)
}
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Result Message
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
2015-07-06 16:58:54 +00:00
filename := doc.filename
2015-07-06 13:52:50 +00:00
*doc = responseRecieved.Result.Document
2015-07-06 16:58:54 +00:00
doc.filename = filename
2015-07-03 18:54:40 +00:00
return nil
}
// SendSticker sends a general document object to recipient.
//
// On success, sticker object would be aliased to its copy on
// the Telegram servers, so sending the same sticker object
// again, won't issue a new upload, but would make a use
// of existing file on Telegram servers.
func (b *Bot) SendSticker(recipient Recipient, sticker *Sticker, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
var responseJSON []byte
2015-07-03 18:54:40 +00:00
var err error
if sticker.Exists() {
params.Set("sticker", sticker.FileID)
2015-07-06 13:52:50 +00:00
responseJSON, err = sendCommand("sendSticker", b.Token, params)
2015-07-03 18:54:40 +00:00
} else {
2015-07-06 13:52:50 +00:00
responseJSON, err = sendFile("sendSticker", b.Token, "sticker",
2015-07-03 18:54:40 +00:00
sticker.filename, params)
}
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Result Message
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
2015-07-06 16:58:54 +00:00
filename := sticker.filename
2015-07-06 13:52:50 +00:00
*sticker = responseRecieved.Result.Sticker
2015-07-06 16:58:54 +00:00
sticker.filename = filename
2015-07-03 18:54:40 +00:00
return nil
}
// SendVideo sends a general document object to recipient.
//
// On success, video object would be aliased to its copy on
// the Telegram servers, so sending the same video object
// again, won't issue a new upload, but would make a use
// of existing file on Telegram servers.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendVideo(recipient Recipient, video *Video, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
var responseJSON []byte
2015-07-03 18:54:40 +00:00
var err error
if video.Exists() {
params.Set("video", video.FileID)
2015-07-06 13:52:50 +00:00
responseJSON, err = sendCommand("sendVideo", b.Token, params)
2015-07-03 18:54:40 +00:00
} else {
2015-07-06 13:52:50 +00:00
responseJSON, err = sendFile("sendVideo", b.Token, "video",
2015-07-03 18:54:40 +00:00
video.filename, params)
}
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Result Message
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
2015-07-06 16:58:54 +00:00
filename := video.filename
2015-07-06 13:52:50 +00:00
*video = responseRecieved.Result.Video
2015-07-06 16:58:54 +00:00
video.filename = filename
2015-07-03 18:54:40 +00:00
return nil
}
// SendLocation sends a general document object to recipient.
//
// On success, video object would be aliased to its copy on
// the Telegram servers, so sending the same video object
// again, won't issue a new upload, but would make a use
// of existing file on Telegram servers.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendLocation(recipient Recipient, geo *Location, options *SendOptions) error {
2015-07-03 18:54:40 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-03 18:54:40 +00:00
params.Set("latitude", fmt.Sprintf("%f", geo.Latitude))
params.Set("longitude", fmt.Sprintf("%f", geo.Longitude))
if options != nil {
embedSendOptions(&params, options)
}
2015-07-06 13:52:50 +00:00
responseJSON, err := sendCommand("sendLocation", b.Token, params)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
var responseRecieved struct {
2015-07-03 18:54:40 +00:00
Ok bool
Result Message
Description string
}
2015-07-06 13:52:50 +00:00
err = json.Unmarshal(responseJSON, &responseRecieved)
2015-07-03 18:54:40 +00:00
if err != nil {
return err
}
2015-07-06 13:52:50 +00:00
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-03 18:54:40 +00:00
}
return nil
}
2015-07-06 16:13:08 +00:00
// SendChatAction updates a chat action for recipient.
//
// Chat action is a status message that recipient would see where
// you typically see "Harry is typing" status message. The only
// difference is that bots' chat actions live only for 5 seconds
// and die just once the client recieves a message from the bot.
//
// Currently, Telegram supports only a narrow range of possible
// actions, these are aligned as constants of this package.
2015-11-16 10:22:37 +00:00
func (b *Bot) SendChatAction(recipient Recipient, action string) error {
2015-07-06 16:13:08 +00:00
params := url.Values{}
params.Set("chat_id", recipient.Destination())
2015-07-06 16:13:08 +00:00
params.Set("action", action)
responseJSON, err := sendCommand("sendChatAction", b.Token, params)
if err != nil {
return err
}
var responseRecieved struct {
Ok bool
Description string
}
err = json.Unmarshal(responseJSON, &responseRecieved)
if err != nil {
return err
}
if !responseRecieved.Ok {
return fmt.Errorf("telebot: %s", responseRecieved.Description)
2015-07-06 16:13:08 +00:00
}
return nil
}