// matchPatterns iterates through the array of registered regular expressions // (patterns) in the order of insertion and checks if they match any part of // the given message's text. If they do then they are invoked with an empty // fields array. // // This does not acquire a lock on the handlerMutex but one should be acquired // for reading before calling this method. func (d *dispatch) matchPatterns(m chat.Message) bool { for _, pair := range d.patterns { if pair.Exp().MatchString(m.Text()) { pair.Handler().Handle(&state{ robot: d.robot, message: m, }) return true } } return false }
// ProcessMessage finds a match for a message and runs its Handler. // If the message is considered a potential command (either sent @ the bot's // name or in a direct message) then the next word after the bot's name is // compared to all registered handlers. If one matches then that handler // function is called with the remaining text seperated by whitespace // (restpecting quotes). If none match then the default handler is called // (with an empty fields array). // // If the message is not a potential command then it is checked against all // registered patterns (with an empty fields array upon a match). // // This opens a read lock on the handlerMutex so new commands cannot be added // while a message is being processed (they will block until processing is // completed) func (d *dispatch) ProcessMessage(m chat.Message) { d.handlerMutex.RLock() defer d.handlerMutex.RUnlock() defer func() { if e := recover(); e != nil { log.Println("Unexpected Panic Processing Message:", m.Text(), " -- Error:", e) return } }() messageText := m.Text() nameMatch := d.botNameRegex.FindString(messageText) if len(nameMatch) > 0 || m.IsDirectMessage() { // slices are cheap (reference original) so if no match then it's ok messageText = messageText[len(nameMatch):] if !d.matchCommands(m, messageText) { d.callDefault(m, messageText) } } else if len(nameMatch) == 0 { d.matchPatterns(m) } }