Merge branch 'develop' into verbose-mode

pull/302/head
demget 4 years ago committed by GitHub
commit 29af30f5ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -139,7 +139,7 @@ func (b *Bot) sendText(to Recipient, text string, opt *SendOptions) (*Message, e
"chat_id": to.Recipient(),
"text": text,
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
data, err := b.Raw("sendMessage", params)
if err != nil {

@ -38,6 +38,7 @@ func NewBot(pref Settings) (*Bot, error) {
handlers: make(map[string]interface{}),
synchronous: pref.Synchronous,
verbose: pref.Verbose,
parseMode: pref.ParseMode,
stop: make(chan struct{}),
reporter: pref.Reporter,
client: client,
@ -67,6 +68,7 @@ type Bot struct {
handlers map[string]interface{}
synchronous bool
verbose bool
parseMode ParseMode
reporter func(error)
stop chan struct{}
client *http.Client
@ -95,6 +97,11 @@ type Settings struct {
// Shows upcoming requests
Verbose bool
// ParseMode used to set default parse mode of all sent messages.
// It attaches to every send, edit or whatever method. You also
// will be able to override the default mode by passing a new one.
ParseMode ParseMode
// Reporter is a callback function that will get called
// on any panics recovered from endpoint handlers.
Reporter func(error)
@ -524,7 +531,7 @@ func (b *Bot) Send(to Recipient, what interface{}, options ...interface{}) (*Mes
// SendAlbum sends multiple instances of media as a single message.
//
// From all existing options, it only supports tb.Silent option.
// From all existing options, it only supports tb.Silent.
func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Message, error) {
if to == nil {
return nil, ErrBadRecipient
@ -596,7 +603,7 @@ func (b *Bot) SendAlbum(to Recipient, a Album, options ...interface{}) ([]Messag
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
data, err := b.sendFiles("sendMediaGroup", files, params)
if err != nil {
@ -655,7 +662,7 @@ func (b *Bot) Forward(to Recipient, msg Editable, options ...interface{}) (*Mess
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
data, err := b.Raw("forwardMessage", params)
if err != nil {
@ -667,11 +674,16 @@ func (b *Bot) Forward(to Recipient, msg Editable, options ...interface{}) (*Mess
// Edit is magic, it lets you change already sent message.
//
// If edited message is sent by the bot, returns it,
// otherwise returns nil and ErrTrueResult.
//
// Use cases:
//
// b.Edit(msg, msg.Text, newMarkup)
// b.Edit(msg, "new <b>text</b>", tb.ModeHTML)
// b.Edit(msg, tb.Location{42.1337, 69.4242})
// b.Edit(m, m.Text, newMarkup)
// b.Edit(m, "new <b>text</b>", tb.ModeHTML)
// b.Edit(m, &tb.ReplyMarkup{...})
// b.Edit(m, &tb.Photo{File: ...})
// b.Edit(m, tb.Location{42.1337, 69.4242})
//
// This function will panic upon nil Editable.
func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Message, error) {
@ -681,6 +693,10 @@ func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Mes
)
switch v := what.(type) {
case *ReplyMarkup:
return b.EditReplyMarkup(msg, v)
case InputMedia:
return b.EditMedia(msg, v, options...)
case string:
method = "editMessageText"
params["text"] = v
@ -702,7 +718,7 @@ func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Mes
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
data, err := b.Raw(method, params)
if err != nil {
@ -715,6 +731,9 @@ func (b *Bot) Edit(msg Editable, what interface{}, options ...interface{}) (*Mes
// EditReplyMarkup edits reply markup of already sent message.
// Pass nil or empty ReplyMarkup to delete it from the message.
//
// If edited message is sent by the bot, returns it,
// otherwise returns nil and ErrTrueResult.
//
// On success, returns edited message object.
// This function will panic upon nil Editable.
func (b *Bot) EditReplyMarkup(msg Editable, markup *ReplyMarkup) (*Message, error) {
@ -747,6 +766,9 @@ func (b *Bot) EditReplyMarkup(msg Editable, markup *ReplyMarkup) (*Message, erro
// EditCaption edits already sent photo caption with known recipient and message id.
//
// If edited message is sent by the bot, returns it,
// otherwise returns nil and ErrTrueResult.
//
// On success, returns edited message object.
// This function will panic upon nil Editable.
func (b *Bot) EditCaption(msg Editable, caption string, options ...interface{}) (*Message, error) {
@ -764,7 +786,7 @@ func (b *Bot) EditCaption(msg Editable, caption string, options ...interface{})
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
data, err := b.Raw("editMessageCaption", params)
if err != nil {
@ -776,10 +798,13 @@ func (b *Bot) EditCaption(msg Editable, caption string, options ...interface{})
// EditMedia edits already sent media with known recipient and message id.
//
// If edited message is sent by the bot, returns it,
// otherwise returns nil and ErrTrueResult.
//
// Use cases:
//
// bot.EditMedia(msg, &tb.Photo{File: tb.FromDisk("chicken.jpg")})
// bot.EditMedia(msg, &tb.Video{File: tb.FromURL("http://video.mp4")})
// b.EditMedia(m, &tb.Photo{File: tb.FromDisk("chicken.jpg")})
// b.EditMedia(m, &tb.Video{File: tb.FromURL("http://video.mp4")})
//
// This function will panic upon nil Editable.
func (b *Bot) EditMedia(msg Editable, media InputMedia, options ...interface{}) (*Message, error) {
@ -875,7 +900,7 @@ func (b *Bot) EditMedia(msg Editable, media InputMedia, options ...interface{})
params := make(map[string]string)
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
if sendOpts != nil {
result.ParseMode = sendOpts.ParseMode
@ -888,7 +913,7 @@ func (b *Bot) EditMedia(msg Editable, media InputMedia, options ...interface{})
data, _ := json.Marshal(result)
params["media"] = string(data)
if chatID == 0 { // If inline message.
if chatID == 0 { // if inline message
params["inline_message_id"] = msgID
} else {
params["chat_id"] = strconv.FormatInt(chatID, 10)
@ -1121,6 +1146,9 @@ func (b *Bot) GetFile(file *File) (io.ReadCloser, error) {
// StopLiveLocation stops broadcasting live message location
// before Location.LivePeriod expires.
//
// If the message is sent by the bot, returns it,
// otherwise returns nil and ErrTrueResult.
//
// It supports tb.ReplyMarkup.
// This function will panic upon nil Editable.
func (b *Bot) StopLiveLocation(msg Editable, options ...interface{}) (*Message, error) {
@ -1132,7 +1160,7 @@ func (b *Bot) StopLiveLocation(msg Editable, options ...interface{}) (*Message,
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
data, err := b.Raw("stopMessageLiveLocation", params)
if err != nil {
@ -1156,7 +1184,7 @@ func (b *Bot) StopPoll(msg Editable, options ...interface{}) (*Poll, error) {
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
data, err := b.Raw("stopPoll", params)
if err != nil {
@ -1289,7 +1317,7 @@ func (b *Bot) Pin(msg Editable, options ...interface{}) error {
}
sendOpts := extractOptions(options)
embedSendOptions(params, sendOpts)
b.embedSendOptions(params, sendOpts)
_, err := b.Raw("pinChatMessage", params)
return err

@ -63,6 +63,7 @@ func TestNewBot(t *testing.T) {
pref.Client = client
pref.Poller = &LongPoller{Timeout: time.Second}
pref.Updates = 50
pref.ParseMode = ModeHTML
pref.offline = true
b, err = NewBot(pref)
@ -71,6 +72,7 @@ func TestNewBot(t *testing.T) {
assert.Equal(t, pref.URL, b.URL)
assert.Equal(t, pref.Poller, b.Poller)
assert.Equal(t, 50, cap(b.Updates))
assert.Equal(t, ModeHTML, b.parseMode)
}
func TestBotHandle(t *testing.T) {
@ -309,23 +311,36 @@ func TestBot(t *testing.T) {
_, err = b.Forward(nil, nil)
assert.Equal(t, ErrBadRecipient, err)
t.Run("Send(what=Sendable)", func(t *testing.T) {
photo := &Photo{
File: File{FileID: photoID},
Caption: t.Name(),
}
photo := &Photo{
File: File{FileID: photoID},
Caption: t.Name(),
}
var msg *Message
msg, err := b.Send(to, photo)
t.Run("Send(what=Sendable)", func(t *testing.T) {
msg, err = b.Send(to, photo)
assert.NoError(t, err)
assert.NotNil(t, msg.Photo)
assert.Equal(t, photo.Caption, msg.Caption)
})
t.Run("EditCaption()+ParseMode", func(t *testing.T) {
b.parseMode = ModeHTML
edited, err := b.EditCaption(msg, "<b>new caption with parse mode</b>")
assert.NoError(t, err)
assert.Equal(t, "new caption with parse mode", edited.Caption)
msg, err = b.EditCaption(msg, "new caption")
b.parseMode = ModeDefault
edited, err = b.EditCaption(msg, "*new caption w/o parse mode*", ModeMarkdown)
assert.NoError(t, err)
assert.Equal(t, "new caption", msg.Caption)
assert.Equal(t, "new caption w/o parse mode", edited.Caption)
})
var msg *Message
t.Run("Edit(what=InputMedia)", func(t *testing.T) {
edited, err := b.Edit(msg, photo)
assert.NoError(t, err)
assert.Equal(t, edited.Photo.FileID, photo.FileID)
})
t.Run("Send(what=string)", func(t *testing.T) {
msg, err = b.Send(to, t.Name())
@ -358,20 +373,8 @@ func TestBot(t *testing.T) {
assert.Error(t, err) // message is not modified
})
t.Run("Edit(what=Location)", func(t *testing.T) {
loc := &Location{Lat: 42, Lng: 69, LivePeriod: 60}
msg, err := b.Send(to, loc)
assert.NoError(t, err)
assert.NotNil(t, msg.Location)
loc = &Location{Lat: loc.Lng, Lng: loc.Lat}
msg, err = b.Edit(msg, *loc)
assert.NoError(t, err)
assert.NotNil(t, msg.Location)
})
t.Run("EditReplyMarkup()", func(t *testing.T) {
markup := &ReplyMarkup{
t.Run("Edit(what=ReplyMarkup)", func(t *testing.T) {
good := &ReplyMarkup{
InlineKeyboard: [][]InlineButton{
{{
Data: "btn",
@ -379,7 +382,7 @@ func TestBot(t *testing.T) {
}},
},
}
badMarkup := &ReplyMarkup{
bad := &ReplyMarkup{
InlineKeyboard: [][]InlineButton{
{{
Data: strings.Repeat("*", 65),
@ -388,18 +391,30 @@ func TestBot(t *testing.T) {
},
}
msg, err := b.EditReplyMarkup(msg, markup)
edited, err := b.Edit(msg, good)
assert.NoError(t, err)
assert.Equal(t, msg.ReplyMarkup.InlineKeyboard, markup.InlineKeyboard)
assert.Equal(t, edited.ReplyMarkup.InlineKeyboard, good.InlineKeyboard)
msg, err = b.EditReplyMarkup(msg, nil)
edited, err = b.EditReplyMarkup(edited, nil)
assert.NoError(t, err)
assert.Nil(t, msg.ReplyMarkup.InlineKeyboard)
assert.Nil(t, edited.ReplyMarkup.InlineKeyboard)
_, err = b.EditReplyMarkup(msg, badMarkup)
_, err = b.Edit(edited, bad)
assert.Equal(t, ErrButtonDataInvalid, err)
})
t.Run("Edit(what=Location)", func(t *testing.T) {
loc := &Location{Lat: 42, Lng: 69, LivePeriod: 60}
edited, err := b.Send(to, loc)
assert.NoError(t, err)
assert.NotNil(t, edited.Location)
loc = &Location{Lat: loc.Lng, Lng: loc.Lat}
edited, err = b.Edit(edited, *loc)
assert.NoError(t, err)
assert.NotNil(t, edited.Location)
})
t.Run("Notify()", func(t *testing.T) {
assert.Equal(t, ErrBadRecipient, b.Notify(nil, Typing))
assert.NoError(t, b.Notify(to, Typing))

@ -1,66 +0,0 @@
package telebot
// Filter is some thing that does filtering for
// incoming updates.
//
// Return false if you wish to sieve the update out.
type Filter interface {
Filter(*Update) bool
}
// FilterFunc is basically a lightweight version of Filter.
type FilterFunc func(*Update) bool
func NewChain(parent Poller) *Chain {
c := &Chain{}
c.Poller = parent
c.Filter = func(upd *Update) bool {
for _, filter := range c.Filters {
switch f := filter.(type) {
case Filter:
if !f.Filter(upd) {
return false
}
case FilterFunc:
if !f(upd) {
return false
}
case func(*Update) bool:
if !f(upd) {
return false
}
}
}
return true
}
return c
}
// Chain is a chain of middle
type Chain struct {
MiddlewarePoller
// (Filter | FilterFunc | func(*Update) bool)
Filters []interface{}
}
// Add accepts either Filter interface or FilterFunc
func (c *Chain) Add(filter interface{}) {
switch filter.(type) {
case Filter:
break
case FilterFunc:
break
case func(*Update) bool:
break
default:
panic("telebot: unsupported filter type")
}
c.Filters = append(c.Filters, filter)
}

@ -70,11 +70,8 @@ func (b *Bot) GetGameScores(user Recipient, msg Editable) ([]GameHighScore, erro
// SetGameScore sets the score of the specified user in a game.
//
// NOTE:
// If the message was sent by the bot, returns the edited Message,
// otherwise returns nil Message and ErrNoGameMessage.
// If you expect successful True result, you must check
// for `telebot: no game message` error.
// If the message was sent by the bot, returns the edited Message,
// otherwise returns nil and ErrTrueResult.
//
func (b *Bot) SetGameScore(user Recipient, msg Editable, score GameHighScore) (*Message, error) {
msgID, chatID := msg.MessageSig()
@ -97,13 +94,5 @@ func (b *Bot) SetGameScore(user Recipient, msg Editable, score GameHighScore) (*
if err != nil {
return nil, err
}
m, err := extractMessage(data)
if err != nil {
return nil, err
}
if m == nil {
return nil, ErrNoGameMessage
}
return m, nil
return extractMessage(data)
}

@ -182,6 +182,13 @@ type GifResult struct {
// Optional. Duration of the GIF.
Duration int `json:"gif_duration,omitempty"`
// URL of the static thumbnail for the result (jpeg or gif).
ThumbURL string `json:"thumb_url"`
// Optional. MIME type of the thumbnail, must be one of
// “image/jpeg”, “image/gif”, or “video/mp4”.
ThumbMIME string `json:"thumb_mime_type,omitempty"`
// Optional. Title for the result.
Title string `json:"title,omitempty"`
@ -192,9 +199,6 @@ type GifResult struct {
// bold, italic, fixed-width text or inline URLs in the media caption.
ParseMode ParseMode `json:"parse_mode,omitempty"`
// URL of the static thumbnail for the result (jpeg or gif).
ThumbURL string `json:"thumb_url"`
// If Cache != "", it'll be used instead
Cache string `json:"gif_file_id,omitempty"`
}
@ -234,6 +238,10 @@ type Mpeg4GifResult struct {
// URL of the static thumbnail (jpeg or gif) for the result.
ThumbURL string `json:"thumb_url,omitempty"`
// Optional. MIME type of the thumbnail, must be one of
// “image/jpeg”, “image/gif”, or “video/mp4”.
ThumbMIME string `json:"thumb_mime_type,omitempty"`
// Optional. Title for the result.
Title string `json:"title,omitempty"`

@ -37,6 +37,9 @@ type Message struct {
// itself is a reply.
ReplyTo *Message `json:"reply_to_message"`
// Shows through which bot the message was sent.
Via *User `json:"via_bot"`
// (Optional) Time of last edit in Unix
LastEdit int64 `json:"edit_date"`

@ -30,7 +30,7 @@ func (p *Photo) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
"caption": p.Caption,
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&p.File, "photo", params, nil)
if err != nil {
@ -58,7 +58,7 @@ func (a *Audio) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
params["duration"] = strconv.Itoa(a.Duration)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&a.File, "audio", params, thumbnailToFilemap(a.Thumbnail))
if err != nil {
@ -91,7 +91,7 @@ func (d *Document) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error
params["file_size"] = strconv.Itoa(d.FileSize)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&d.File, "document", params, thumbnailToFilemap(d.Thumbnail))
if err != nil {
@ -110,7 +110,7 @@ func (s *Sticker) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error)
params := map[string]string{
"chat_id": to.Recipient(),
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&s.File, "sticker", params, nil)
if err != nil {
@ -144,7 +144,7 @@ func (v *Video) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
params["supports_streaming"] = "true"
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&v.File, "video", params, thumbnailToFilemap(v.Thumbnail))
if err != nil {
@ -191,7 +191,7 @@ func (a *Animation) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, erro
params["file_name"] = filepath.Base(a.File.FileLocal)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&a.File, "animation", params, nil)
if err != nil {
@ -215,7 +215,7 @@ func (v *Voice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
params["duration"] = strconv.Itoa(v.Duration)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&v.File, "voice", params, nil)
if err != nil {
@ -241,7 +241,7 @@ func (v *VideoNote) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, erro
params["length"] = strconv.Itoa(v.Length)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
msg, err := b.sendObject(&v.File, "videoNote", params, thumbnailToFilemap(v.Thumbnail))
if err != nil {
@ -262,7 +262,7 @@ func (x *Location) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error
"longitude": fmt.Sprintf("%f", x.Lng),
"live_period": strconv.Itoa(x.LivePeriod),
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
data, err := b.Raw("sendLocation", params)
if err != nil {
@ -283,7 +283,7 @@ func (v *Venue) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
"foursquare_id": v.FoursquareID,
"foursquare_type": v.FoursquareType,
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
data, err := b.Raw("sendVenue", params)
if err != nil {
@ -329,7 +329,7 @@ func (i *Invoice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error)
data, _ := json.Marshal(i.Prices)
params["prices"] = string(data)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
data, err := b.Raw("sendInvoice", params)
if err != nil {
@ -359,7 +359,7 @@ func (p *Poll) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
} else if p.CloseUnixdate != 0 {
params["close_date"] = strconv.FormatInt(p.CloseUnixdate, 10)
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
var options []string
for _, o := range p.Options {
@ -382,7 +382,7 @@ func (d *Dice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
"chat_id": to.Recipient(),
"emoji": string(d.Type),
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
data, err := b.Raw("sendDice", params)
if err != nil {
@ -398,7 +398,7 @@ func (g *Game) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
"chat_id": to.Recipient(),
"game_short_name": g.Title,
}
embedSendOptions(params, opt)
b.embedSendOptions(params, opt)
data, err := b.Raw("sendGame", params)
if err != nil {

@ -13,11 +13,7 @@ type Sticker struct {
Animated bool `json:"is_animated"`
Thumbnail *Photo `json:"thumb"`
Emoji string `json:"emoji"`
Name string `json:"name"`
SetName string `json:"set_name"`
PNG *File `json:"png_sticker"`
TGS *File `json:"tgs_file"`
Emojis string `json:"emojis"`
MaskPosition *MaskPosition `json:"mask_position"`
}
@ -26,12 +22,12 @@ type StickerSet struct {
Name string `json:"name"`
Title string `json:"title"`
Animated bool `json:"is_animated"`
ContainsMasks bool `json:"contains_masks"`
Stickers []Sticker `json:"stickers"`
Thumbnail *Photo `json:"thumb"`
PNG *File `json:"png_sticker"`
TGS *File `json:"tgs_file"`
TGS *File `json:"tgs_sticker"`
Emojis string `json:"emojis"`
ContainsMasks bool `json:"contains_masks"`
MaskPosition *MaskPosition `json:"mask_position"`
}
@ -44,15 +40,6 @@ type MaskPosition struct {
Scale float32 `json:"scale"`
}
// StickerSetParams describes the payload in creating new sticker set api-method.
type StickerSetParams struct {
UserID int
Name string
Title string
PngSticker *File
Emojis string
}
// UploadStickerFile uploads a .PNG file with a sticker for later use.
func (b *Bot) UploadStickerFile(to Recipient, png *File) (*File, error) {
files := map[string]File{
@ -123,7 +110,7 @@ func (b *Bot) CreateNewStickerSet(to Recipient, s StickerSet) error {
}
// AddStickerToSet adds new sticker to existing sticker set.
func (b *Bot) AddStickerToSet(to Recipient, s Sticker) error {
func (b *Bot) AddStickerToSet(to Recipient, s StickerSet) error {
files := make(map[string]File)
if s.PNG != nil {
files["png_sticker"] = *s.PNG
@ -176,7 +163,7 @@ func (b *Bot) DeleteStickerFromSet(sticker string) error {
//
// Animated sticker set thumbnail can't be uploaded via HTTP URL.
//
func (b *Bot) SetStickerSetThumb(to Recipient, s Sticker) error {
func (b *Bot) SetStickerSetThumb(to Recipient, s StickerSet) error {
files := map[string]File{}
if s.PNG != nil {
files["thumb"] = *s.PNG

@ -34,7 +34,7 @@ var (
ErrBadRecipient = errors.New("telebot: recipient is nil")
ErrUnsupportedWhat = errors.New("telebot: unsupported what argument")
ErrCouldNotUpdate = errors.New("telebot: could not fetch new updates")
ErrNoGameMessage = errors.New("telebot: no game message")
ErrTrueResult = errors.New("telebot: result is True")
)
const DefaultApiURL = "https://api.telegram.org"
@ -218,4 +218,5 @@ type DiceType string
var (
Cube = &Dice{Type: "🎲"}
Dart = &Dice{Type: "🎯"}
Ball = &Dice{Type: "🏀"}
)

@ -70,6 +70,15 @@ func extractMessage(data []byte) (*Message, error) {
Result *Message
}
if err := json.Unmarshal(data, &resp); err != nil {
var resp struct {
Result bool
}
if err := json.Unmarshal(data, &resp); err != nil {
return nil, wrapError(err)
}
if resp.Result {
return nil, ErrTrueResult
}
return nil, wrapError(err)
}
return resp.Result, nil
@ -123,7 +132,11 @@ func extractOptions(how []interface{}) *SendOptions {
return opts
}
func embedSendOptions(params map[string]string, opt *SendOptions) {
func (b *Bot) embedSendOptions(params map[string]string, opt *SendOptions) {
if b.parseMode != ModeDefault {
params["parse_mode"] = b.parseMode
}
if opt == nil {
return
}

@ -13,6 +13,16 @@ func TestExtractOk(t *testing.T) {
data = []byte(`{"ok":false,"error_code":429,"description":"Too Many Requests: retry after 8","parameters":{"retry_after":8}}`)
assert.Error(t, extractOk(data))
data = []byte(`{"ok":false,"error_code":400,"description":"Bad Request: reply message not found"}`) // Also check the old format
data = []byte(`{"ok":false,"error_code":400,"description":"Bad Request: reply message not found"}`)
assert.EqualError(t, extractOk(data), ErrToReplyNotFound.Error())
}
func TestExtractMessage(t *testing.T) {
data := []byte(`{"ok":true,"result":true}`)
_, err := extractMessage(data)
assert.Equal(t, ErrTrueResult, err)
data = []byte(`{"ok":true,"result":{"foo":"bar"}}`)
_, err = extractMessage(data)
assert.NoError(t, err)
}

@ -17,9 +17,9 @@ type WebhookTLS struct {
// A WebhookEndpoint describes the endpoint to which telegram will send its requests.
// This must be a public URL and can be a loadbalancer or something similar. If the
// endpoint uses TLS and the certificate is selfsigned you have to add the certificate
// endpoint uses TLS and the certificate is self-signed you have to add the certificate
// path of this certificate so telegram will trust it. This field can be ignored if you
// have a trusted certifcate (letsencrypt, ...).
// have a trusted certificate (letsencrypt, ...).
type WebhookEndpoint struct {
PublicURL string
Cert string
@ -28,13 +28,16 @@ type WebhookEndpoint struct {
// A Webhook configures the poller for webhooks. It opens a port on the given
// listen address. If TLS is filled, the listener will use the key and cert to open
// a secure port. Otherwise it will use plain HTTP.
//
// If you have a loadbalancer ore other infrastructure in front of your service, you
// must fill the Endpoint structure so this poller will send this data to telegram. If
// you leave these values empty, your local address will be sent to telegram which is mostly
// not what you want (at least while developing). If you have a single instance of your
// bot you should consider to use the LongPoller instead of a WebHook.
//
// You can also leave the Listen field empty. In this case it is up to the caller to
// add the Webhook to a http-mux.
//
type Webhook struct {
Listen string `json:"url"`
MaxConnections int `json:"max_connections"`

Loading…
Cancel
Save