From 337be69aa38afdbe348b4fef13ee5894a2d1380e Mon Sep 17 00:00:00 2001 From: Ian Byrd Date: Tue, 21 Nov 2017 04:22:45 +0200 Subject: [PATCH] Routing system: final touches! --- bot.go | 195 +++++++++++++++++++++++++++++++++-------------------- handle.go | 76 --------------------- telebot.go | 16 ++--- 3 files changed, 129 insertions(+), 158 deletions(-) delete mode 100644 handle.go diff --git a/bot.go b/bot.go index 8bcbc32..e235cfb 100644 --- a/bot.go +++ b/bot.go @@ -3,31 +3,13 @@ package telebot import ( "encoding/json" "fmt" + "regexp" "strconv" + "strings" "github.com/pkg/errors" ) -// Bot represents a separate Telegram bot instance. -type Bot struct { - Token string - Me *User - - Updates chan Update - Messages chan Message - Queries chan Query - Callbacks chan Callback - - // Telebot debugging channel. If present, Telebot - // will use it to report all occuring errors. - Errors chan error - - // Poller is the update provider. - Poller Poller - - handlers map[string]interface{} -} - // NewBot does try to build a Bot with token `token`, which // is a secret API key assigned to particular bot. func NewBot(pref Settings) (*Bot, error) { @@ -43,18 +25,6 @@ func NewBot(pref Settings) (*Bot, error) { handlers: make(map[string]interface{}), } - if pref.Messages != 0 { - bot.Messages = make(chan Message, pref.Messages) - } - - if pref.Queries != 0 { - bot.Queries = make(chan Query, pref.Queries) - } - - if pref.Callbacks != 0 { - bot.Callbacks = make(chan Callback, pref.Callbacks) - } - user, err := bot.getMe() if err != nil { return nil, err @@ -64,21 +34,25 @@ func NewBot(pref Settings) (*Bot, error) { return bot, nil } +// Bot represents a separate Telegram bot instance. +type Bot struct { + Me *User + Token string + Updates chan Update + Poller Poller + Errors chan error + + handlers map[string]interface{} +} + // Settings represents a utility struct for passing certain // properties of a bot around and is required to make bots. type Settings struct { // Telegram token Token string - // Telegram serves three types of updates: messages, - // inline queries and callbacks. - // - // The following three variables set the capacity of - // each of the receiving channels. - Updates int // Default: 100 - Messages int - Queries int - Callbacks int + // Updates channel capacity + Updates int // Default: 100 // Poller is the provider of Updates. Poller Poller @@ -96,6 +70,32 @@ type Update struct { Query *Query `json:"inline_query,omitempty"` } +// Handle lets you set the handler for some command name or +// one of the supported endpoints. +// +// See Endpoint. +func (b *Bot) Handle(endpoint string, handler interface{}) { + b.handlers[endpoint] = handler +} + +var cmdRx = regexp.MustCompile(`^\/(\w+)(@(\w+))?(\s|$)`) + +func (b *Bot) handleCommand(m *Message, cmdName, cmdBot string) bool { + // Group-syntax: "/cmd@bot" + if cmdBot != "" && !strings.EqualFold(b.Me.Username, cmdBot) { + return false + } + + if handler, ok := b.handlers[cmdName]; ok { + if handler, ok := handler.(func(*Message)); ok { + go handler(m) + return true + } + } + + return false +} + // Start brings bot into motion by consuming incoming // updates (see Bot.Updates channel). func (b *Bot) Start() { @@ -105,51 +105,75 @@ func (b *Bot) Start() { go b.Poller.Poll(b, b.Updates) - if b.Messages != nil { - go b.handleMessages(b.Messages) - } - - if b.Queries != nil { - go b.handleQueries(b.Queries) - } - - if b.Callbacks != nil { - go b.handleCallbacks(b.Callbacks) - } - - fmt.Println("start ranging...") for upd := range b.Updates { - fmt.Println(upd) - if b.Messages != nil { - if upd.Message != nil { - fmt.Println("receiving 1:", upd.Message.Text) - b.Messages <- *upd.Message - continue + if upd.Message != nil { + m := upd.Message + + // Text message + if m.Text != "" { + match := cmdRx.FindAllStringSubmatch(m.Text, -1) + + // Command found + if match != nil { + if b.handleCommand(m, match[0][1], match[0][3]) { + continue + } + } } - if upd.EditedMessage != nil { - b.Messages <- *upd.EditedMessage - continue + // OnMessage + if handler, ok := b.handlers[string(OnMessage)]; ok { + if handler, ok := handler.(func(*Message)); ok { + go handler(m) + continue + } } + continue + } - if upd.ChannelPost != nil { - b.Messages <- *upd.ChannelPost - continue + if upd.EditedMessage != nil { + if handler, ok := b.handlers[OnEditedMessage]; ok { + if handler, ok := handler.(func(*Message)); ok { + handler(upd.EditedMessage) + } } + continue + } - if upd.EditedChannelPost != nil { - b.Messages <- *upd.EditedChannelPost - continue + if upd.ChannelPost != nil { + if handler, ok := b.handlers[OnChannelPost]; ok { + if handler, ok := handler.(func(*Message)); ok { + handler(upd.ChannelPost) + } } + continue } - if upd.Callback != nil && b.Callbacks != nil { - b.Callbacks <- *upd.Callback + if upd.EditedChannelPost != nil { + if handler, ok := b.handlers[OnEditedChannelPost]; ok { + if handler, ok := handler.(func(*Message)); ok { + handler(upd.EditedChannelPost) + } + } continue } - if upd.Query != nil && b.Queries != nil { - b.Queries <- *upd.Query + if upd.Callback != nil { + if handler, ok := b.handlers[OnCallback]; ok { + if handler, ok := handler.(func(*Callback)); ok { + handler(upd.Callback) + } + } + continue + } + + if upd.Query != nil { + if handler, ok := b.handlers[OnQuery]; ok { + if handler, ok := handler.(func(*Query)); ok { + handler(upd.Query) + } + } + continue } } } @@ -571,3 +595,28 @@ func (b *Bot) FileURLByID(fileID string) (string, error) { } return "https://api.telegram.org/file/bot" + b.Token + "/" + f.FilePath, nil } + +func (b *Bot) handleMessages(messages chan Message) { + for m := range messages { + + // Text message + if m.Text != "" { + match := cmdRx.FindAllStringSubmatch(m.Text, -1) + + // Command found + if match != nil { + if b.handleCommand(&m, match[0][1], match[0][3]) { + continue + } + } + } + + // OnMessage + if handler, ok := b.handlers[string(OnMessage)]; ok { + if handler, ok := handler.(func(*Message)); ok { + go handler(&m) + continue + } + } + } +} diff --git a/handle.go b/handle.go deleted file mode 100644 index 71d2e4d..0000000 --- a/handle.go +++ /dev/null @@ -1,76 +0,0 @@ -package telebot - -import ( - "regexp" - "strings" -) - -// Handle lets you set the handler for some command name or -// one of the supported endpoints. -// -// See Endpoint. -func (b *Bot) Handle(endpoint, handler interface{}) { - if cmd, ok := endpoint.(string); ok { - b.handlers[cmd] = handler - - } else if end, ok := endpoint.(Endpoint); ok { - b.handlers[string(end)] = handler - - } else { - panic("Handle() only supports patterns and endpoints") - } -} - -var cmdRx = regexp.MustCompile(`^\/(\w+)(@(\w+))?`) - -func (b *Bot) handleMessages(messages chan Message) { - for m := range messages { - // Text message - if m.Text != "" { - match := cmdRx.FindAllStringSubmatch(m.Text, -1) - - // Command found - if match != nil { - if b.handleCommand(&m, match[0][1], match[0][3]) { - continue - } - } - - // Feeding it to OnMessage if one exists. - if handler, ok := b.handlers[string(OnMessage)]; ok { - if handler, ok := handler.(func(*Message)); ok { - go handler(&m) - continue - } - } - } - } -} - -func (b *Bot) handleCommand(m *Message, cmdName, cmdBot string) bool { - // Group-syntax: "/cmd@bot" - if cmdBot != "" && !strings.EqualFold(b.Me.Username, cmdBot) { - return false - } - - if handler, ok := b.handlers[cmdName]; ok { - if handler, ok := handler.(func(*Message)); ok { - go handler(m) - return true - } - } - - return false -} - -func (b *Bot) handleQueries(queries chan Query) { - for _ = range queries { - - } -} - -func (b *Bot) handleCallbacks(callbacks chan Callback) { - for _ = range callbacks { - - } -} diff --git a/telebot.go b/telebot.go index ae625bf..0414df9 100644 --- a/telebot.go +++ b/telebot.go @@ -27,19 +27,17 @@ // package telebot -// Endpoint is one of the possible events Handle() can deal with. +// These are one of the possible events Handle() can deal with. // // For convenience, all Telebot-provided endpoints start with // an "alert" character \a. -type Endpoint string - const ( - OnMessage Endpoint = "\amessage" - OnEditedMessage Endpoint = "\aedited_msg" - OnQuery Endpoint = "\aquery" - OnCallback Endpoint = "\acallback" - OnChannelPost Endpoint = "\achan_post" - OnEditedChannelPost Endpoint = "\achan_post" + OnMessage = "\amessage" + OnEditedMessage = "\aedited_msg" + OnQuery = "\aquery" + OnCallback = "\acallback" + OnChannelPost = "\achan_post" + OnEditedChannelPost = "\achan_post" ) // ChatAction is a client-side status indicating bot activity.