You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
471 lines
12 KiB
471 lines
12 KiB
package telebot |
|
|
|
import ( |
|
"errors" |
|
"strings" |
|
"sync" |
|
"time" |
|
) |
|
|
|
// HandlerFunc represents a handler function, which is |
|
// used to handle actual endpoints. |
|
type HandlerFunc func(Context) error |
|
|
|
// Context wraps an update and represents the context of current event. |
|
type Context interface { |
|
// Bot returns the bot instance. |
|
Bot() *Bot |
|
|
|
// Update returns the original update. |
|
Update() Update |
|
|
|
// Message returns stored message if such presented. |
|
Message() *Message |
|
|
|
// Callback returns stored callback if such presented. |
|
Callback() *Callback |
|
|
|
// Query returns stored query if such presented. |
|
Query() *Query |
|
|
|
// InlineResult returns stored inline result if such presented. |
|
InlineResult() *InlineResult |
|
|
|
// ShippingQuery returns stored shipping query if such presented. |
|
ShippingQuery() *ShippingQuery |
|
|
|
// PreCheckoutQuery returns stored pre checkout query if such presented. |
|
PreCheckoutQuery() *PreCheckoutQuery |
|
|
|
// Poll returns stored poll if such presented. |
|
Poll() *Poll |
|
|
|
// PollAnswer returns stored poll answer if such presented. |
|
PollAnswer() *PollAnswer |
|
|
|
// ChatMember returns chat member changes. |
|
ChatMember() *ChatMemberUpdate |
|
|
|
// ChatJoinRequest returns cha |
|
ChatJoinRequest() *ChatJoinRequest |
|
|
|
// Migration returns both migration from and to chat IDs. |
|
Migration() (int64, int64) |
|
|
|
// Sender returns the current recipient, depending on the context type. |
|
// Returns nil if user is not presented. |
|
Sender() *User |
|
|
|
// Chat returns the current chat, depending on the context type. |
|
// Returns nil if chat is not presented. |
|
Chat() *Chat |
|
|
|
// Recipient combines both Sender and Chat functions. If there is no user |
|
// the chat will be returned. The native context cannot be without sender, |
|
// but it is useful in the case when the context created intentionally |
|
// by the NewContext constructor and have only Chat field inside. |
|
Recipient() Recipient |
|
|
|
// Text returns the message text, depending on the context type. |
|
// In the case when no related data presented, returns an empty string. |
|
Text() string |
|
|
|
// Data returns the current data, depending on the context type. |
|
// If the context contains command, returns its arguments string. |
|
// If the context contains payment, returns its payload. |
|
// In the case when no related data presented, returns an empty string. |
|
Data() string |
|
|
|
// Args returns a raw slice of command or callback arguments as strings. |
|
// The message arguments split by space, while the callback's ones by a "|" symbol. |
|
Args() []string |
|
|
|
// Send sends a message to the current recipient. |
|
// See Send from bot.go. |
|
Send(what interface{}, opts ...interface{}) error |
|
|
|
// SendAlbum sends an album to the current recipient. |
|
// See SendAlbum from bot.go. |
|
SendAlbum(a Album, opts ...interface{}) error |
|
|
|
// Reply replies to the current message. |
|
// See Reply from bot.go. |
|
Reply(what interface{}, opts ...interface{}) error |
|
|
|
// Forward forwards the given message to the current recipient. |
|
// See Forward from bot.go. |
|
Forward(msg Editable, opts ...interface{}) error |
|
|
|
// ForwardTo forwards the current message to the given recipient. |
|
// See Forward from bot.go |
|
ForwardTo(to Recipient, opts ...interface{}) error |
|
|
|
// Edit edits the current message. |
|
// See Edit from bot.go. |
|
Edit(what interface{}, opts ...interface{}) error |
|
|
|
// EditCaption edits the caption of the current message. |
|
// See EditCaption from bot.go. |
|
EditCaption(caption string, opts ...interface{}) error |
|
|
|
// EditOrSend edits the current message if the update is callback, |
|
// otherwise the content is sent to the chat as a separate message. |
|
EditOrSend(what interface{}, opts ...interface{}) error |
|
|
|
// EditOrReply edits the current message if the update is callback, |
|
// otherwise the content is replied as a separate message. |
|
EditOrReply(what interface{}, opts ...interface{}) error |
|
|
|
// Delete removes the current message. |
|
// See Delete from bot.go. |
|
Delete() error |
|
|
|
// DeleteAfter waits for the duration to elapse and then removes the |
|
// message. It handles an error automatically using b.OnError callback. |
|
// It returns a Timer that can be used to cancel the call using its Stop method. |
|
DeleteAfter(d time.Duration) *time.Timer |
|
|
|
// Notify updates the chat action for the current recipient. |
|
// See Notify from bot.go. |
|
Notify(action ChatAction) error |
|
|
|
// Ship replies to the current shipping query. |
|
// See Ship from bot.go. |
|
Ship(what ...interface{}) error |
|
|
|
// Accept finalizes the current deal. |
|
// See Accept from bot.go. |
|
Accept(errorMessage ...string) error |
|
|
|
// Answer sends a response to the current inline query. |
|
// See Answer from bot.go. |
|
Answer(resp *QueryResponse) error |
|
|
|
// Respond sends a response for the current callback query. |
|
// See Respond from bot.go. |
|
Respond(resp ...*CallbackResponse) error |
|
|
|
// Get retrieves data from the context. |
|
Get(key string) interface{} |
|
|
|
// Set saves data in the context. |
|
Set(key string, val interface{}) |
|
} |
|
|
|
// nativeContext is a native implementation of the Context interface. |
|
// "context" is taken by context package, maybe there is a better name. |
|
type nativeContext struct { |
|
b *Bot |
|
u Update |
|
lock sync.RWMutex |
|
store map[string]interface{} |
|
} |
|
|
|
func (c *nativeContext) Bot() *Bot { |
|
return c.b |
|
} |
|
|
|
func (c *nativeContext) Update() Update { |
|
return c.u |
|
} |
|
|
|
func (c *nativeContext) Message() *Message { |
|
switch { |
|
case c.u.Message != nil: |
|
return c.u.Message |
|
case c.u.Callback != nil: |
|
return c.u.Callback.Message |
|
case c.u.EditedMessage != nil: |
|
return c.u.EditedMessage |
|
case c.u.ChannelPost != nil: |
|
if c.u.ChannelPost.PinnedMessage != nil { |
|
return c.u.ChannelPost.PinnedMessage |
|
} |
|
return c.u.ChannelPost |
|
case c.u.EditedChannelPost != nil: |
|
return c.u.EditedChannelPost |
|
default: |
|
return nil |
|
} |
|
} |
|
|
|
func (c *nativeContext) Callback() *Callback { |
|
return c.u.Callback |
|
} |
|
|
|
func (c *nativeContext) Query() *Query { |
|
return c.u.Query |
|
} |
|
|
|
func (c *nativeContext) InlineResult() *InlineResult { |
|
return c.u.InlineResult |
|
} |
|
|
|
func (c *nativeContext) ShippingQuery() *ShippingQuery { |
|
return c.u.ShippingQuery |
|
} |
|
|
|
func (c *nativeContext) PreCheckoutQuery() *PreCheckoutQuery { |
|
return c.u.PreCheckoutQuery |
|
} |
|
|
|
func (c *nativeContext) ChatMember() *ChatMemberUpdate { |
|
switch { |
|
case c.u.ChatMember != nil: |
|
return c.u.ChatMember |
|
case c.u.MyChatMember != nil: |
|
return c.u.MyChatMember |
|
default: |
|
return nil |
|
} |
|
} |
|
|
|
func (c *nativeContext) ChatJoinRequest() *ChatJoinRequest { |
|
return c.u.ChatJoinRequest |
|
} |
|
|
|
func (c *nativeContext) Poll() *Poll { |
|
return c.u.Poll |
|
} |
|
|
|
func (c *nativeContext) PollAnswer() *PollAnswer { |
|
return c.u.PollAnswer |
|
} |
|
|
|
func (c *nativeContext) Migration() (int64, int64) { |
|
return c.u.Message.MigrateFrom, c.u.Message.MigrateTo |
|
} |
|
|
|
func (c *nativeContext) Sender() *User { |
|
switch { |
|
case c.u.Callback != nil: |
|
return c.u.Callback.Sender |
|
case c.Message() != nil: |
|
return c.Message().Sender |
|
case c.u.Query != nil: |
|
return c.u.Query.Sender |
|
case c.u.InlineResult != nil: |
|
return c.u.InlineResult.Sender |
|
case c.u.ShippingQuery != nil: |
|
return c.u.ShippingQuery.Sender |
|
case c.u.PreCheckoutQuery != nil: |
|
return c.u.PreCheckoutQuery.Sender |
|
case c.u.PollAnswer != nil: |
|
return c.u.PollAnswer.Sender |
|
case c.u.MyChatMember != nil: |
|
return c.u.MyChatMember.Sender |
|
case c.u.ChatMember != nil: |
|
return c.u.ChatMember.Sender |
|
case c.u.ChatJoinRequest != nil: |
|
return c.u.ChatJoinRequest.Sender |
|
default: |
|
return nil |
|
} |
|
} |
|
|
|
func (c *nativeContext) Chat() *Chat { |
|
switch { |
|
case c.Message() != nil: |
|
return c.Message().Chat |
|
case c.u.MyChatMember != nil: |
|
return c.u.MyChatMember.Chat |
|
case c.u.ChatMember != nil: |
|
return c.u.ChatMember.Chat |
|
case c.u.ChatJoinRequest != nil: |
|
return c.u.ChatJoinRequest.Chat |
|
default: |
|
return nil |
|
} |
|
} |
|
|
|
func (c *nativeContext) Recipient() Recipient { |
|
chat := c.Chat() |
|
if chat != nil { |
|
return chat |
|
} |
|
return c.Sender() |
|
} |
|
|
|
func (c *nativeContext) Text() string { |
|
m := c.Message() |
|
if m == nil { |
|
return "" |
|
} |
|
if m.Caption != "" { |
|
return m.Caption |
|
} |
|
return m.Text |
|
} |
|
|
|
func (c *nativeContext) Data() string { |
|
switch { |
|
case c.u.Message != nil: |
|
return c.u.Message.Payload |
|
case c.u.Callback != nil: |
|
return c.u.Callback.Data |
|
case c.u.Query != nil: |
|
return c.u.Query.Text |
|
case c.u.InlineResult != nil: |
|
return c.u.InlineResult.Query |
|
case c.u.ShippingQuery != nil: |
|
return c.u.ShippingQuery.Payload |
|
case c.u.PreCheckoutQuery != nil: |
|
return c.u.PreCheckoutQuery.Payload |
|
default: |
|
return "" |
|
} |
|
} |
|
|
|
func (c *nativeContext) Args() []string { |
|
switch { |
|
case c.u.Message != nil: |
|
payload := strings.Trim(c.u.Message.Payload, " ") |
|
if payload != "" { |
|
return strings.Split(payload, " ") |
|
} |
|
case c.u.Callback != nil: |
|
return strings.Split(c.u.Callback.Data, "|") |
|
case c.u.Query != nil: |
|
return strings.Split(c.u.Query.Text, " ") |
|
case c.u.InlineResult != nil: |
|
return strings.Split(c.u.InlineResult.Query, " ") |
|
} |
|
return nil |
|
} |
|
|
|
func (c *nativeContext) Send(what interface{}, opts ...interface{}) error { |
|
_, err := c.b.Send(c.Recipient(), what, opts...) |
|
return err |
|
} |
|
|
|
func (c *nativeContext) SendAlbum(a Album, opts ...interface{}) error { |
|
_, err := c.b.SendAlbum(c.Recipient(), a, opts...) |
|
return err |
|
} |
|
|
|
func (c *nativeContext) Reply(what interface{}, opts ...interface{}) error { |
|
msg := c.Message() |
|
if msg == nil { |
|
return ErrBadContext |
|
} |
|
_, err := c.b.Reply(msg, what, opts...) |
|
return err |
|
} |
|
|
|
func (c *nativeContext) Forward(msg Editable, opts ...interface{}) error { |
|
_, err := c.b.Forward(c.Recipient(), msg, opts...) |
|
return err |
|
} |
|
|
|
func (c *nativeContext) ForwardTo(to Recipient, opts ...interface{}) error { |
|
msg := c.Message() |
|
if msg == nil { |
|
return ErrBadContext |
|
} |
|
_, err := c.b.Forward(to, msg, opts...) |
|
return err |
|
} |
|
|
|
func (c *nativeContext) Edit(what interface{}, opts ...interface{}) error { |
|
if c.u.InlineResult != nil { |
|
_, err := c.b.Edit(c.u.InlineResult, what, opts...) |
|
return err |
|
} |
|
if c.u.Callback != nil { |
|
_, err := c.b.Edit(c.u.Callback, what, opts...) |
|
return err |
|
} |
|
return ErrBadContext |
|
} |
|
|
|
func (c *nativeContext) EditCaption(caption string, opts ...interface{}) error { |
|
if c.u.InlineResult != nil { |
|
_, err := c.b.EditCaption(c.u.InlineResult, caption, opts...) |
|
return err |
|
} |
|
if c.u.Callback != nil { |
|
_, err := c.b.EditCaption(c.u.Callback, caption, opts...) |
|
return err |
|
} |
|
return ErrBadContext |
|
} |
|
|
|
func (c *nativeContext) EditOrSend(what interface{}, opts ...interface{}) error { |
|
err := c.Edit(what, opts...) |
|
if err == ErrBadContext { |
|
return c.Send(what, opts...) |
|
} |
|
return err |
|
} |
|
|
|
func (c *nativeContext) EditOrReply(what interface{}, opts ...interface{}) error { |
|
err := c.Edit(what, opts...) |
|
if err == ErrBadContext { |
|
return c.Reply(what, opts...) |
|
} |
|
return err |
|
} |
|
|
|
func (c *nativeContext) Delete() error { |
|
msg := c.Message() |
|
if msg == nil { |
|
return ErrBadContext |
|
} |
|
return c.b.Delete(msg) |
|
} |
|
|
|
func (c *nativeContext) DeleteAfter(d time.Duration) *time.Timer { |
|
return time.AfterFunc(d, func() { |
|
if err := c.Delete(); err != nil { |
|
c.b.OnError(err, c) |
|
} |
|
}) |
|
} |
|
|
|
func (c *nativeContext) Notify(action ChatAction) error { |
|
return c.b.Notify(c.Recipient(), action) |
|
} |
|
|
|
func (c *nativeContext) Ship(what ...interface{}) error { |
|
if c.u.ShippingQuery == nil { |
|
return errors.New("telebot: context shipping query is nil") |
|
} |
|
return c.b.Ship(c.u.ShippingQuery, what...) |
|
} |
|
|
|
func (c *nativeContext) Accept(errorMessage ...string) error { |
|
if c.u.PreCheckoutQuery == nil { |
|
return errors.New("telebot: context pre checkout query is nil") |
|
} |
|
return c.b.Accept(c.u.PreCheckoutQuery, errorMessage...) |
|
} |
|
|
|
func (c *nativeContext) Answer(resp *QueryResponse) error { |
|
if c.u.Query == nil { |
|
return errors.New("telebot: context inline query is nil") |
|
} |
|
return c.b.Answer(c.u.Query, resp) |
|
} |
|
|
|
func (c *nativeContext) Respond(resp ...*CallbackResponse) error { |
|
if c.u.Callback == nil { |
|
return errors.New("telebot: context callback is nil") |
|
} |
|
return c.b.Respond(c.u.Callback, resp...) |
|
} |
|
|
|
func (c *nativeContext) Set(key string, value interface{}) { |
|
c.lock.Lock() |
|
defer c.lock.Unlock() |
|
|
|
if c.store == nil { |
|
c.store = make(map[string]interface{}) |
|
} |
|
c.store[key] = value |
|
} |
|
|
|
func (c *nativeContext) Get(key string) interface{} { |
|
c.lock.RLock() |
|
defer c.lock.RUnlock() |
|
return c.store[key] |
|
}
|
|
|