catbase/plugins/factoid.go

184 lines
4.9 KiB
Go
Raw Normal View History

2012-08-26 19:15:04 +00:00
package plugins
import (
"bitbucket.org/phlyingpenguin/godeepintir/bot"
"fmt"
"labix.org/v2/mgo"
"labix.org/v2/mgo/bson"
"math/rand"
"regexp"
"strings"
"time"
)
// This is a factoid plugin to serve as an example and quick copy/paste for new plugins.
// factoid stores info about our factoid for lookup and later interaction
type factoid struct {
Id int
Trigger string
Operator string
FullText string
CreatedBy string
}
type FactoidPlugin struct {
Bot *bot.Bot
Coll *mgo.Collection
NotFound []string
2012-08-26 19:15:04 +00:00
}
// NewFactoidPlugin creates a new FactoidPlugin with the Plugin interface
func NewFactoidPlugin(bot *bot.Bot) *FactoidPlugin {
p := &FactoidPlugin{
Bot: bot,
Coll: nil,
NotFound: []string{
"I don't know.",
"NONONONO",
"((",
"*pukes*",
"NOPE! NOPE! NOPE!",
"One time, I learned how to jump rope.",
},
2012-08-26 19:15:04 +00:00
}
p.LoadData()
return p
}
func (p *FactoidPlugin) findAction(message string) string {
r, err := regexp.Compile("<.+?>| is | are ")
2012-08-26 19:15:04 +00:00
if err != nil {
panic(err)
}
action := r.FindString(message)
return action
}
func (p *FactoidPlugin) learnFact(message bot.Message, trigger, operator, fact string) bool {
2012-08-26 19:15:04 +00:00
// if it's an action, we only want the fact part of it in the fulltext
full := fact
if operator != "action" && operator != "reply" {
full = fmt.Sprintf("%s %s %s", trigger, operator, fact)
}
trigger = strings.ToLower(trigger)
q := p.Coll.Find(bson.M{"trigger": trigger, "fulltext": full})
if n, _ := q.Count(); n != 0 {
return false
}
2012-08-26 19:15:04 +00:00
newfact := factoid{
Id: 0,
Trigger: trigger,
Operator: operator,
FullText: full,
CreatedBy: message.User.Name,
}
p.Coll.Insert(newfact)
return true
2012-08-26 19:15:04 +00:00
}
func (p *FactoidPlugin) findTrigger(message string) (bool, *factoid) {
2012-08-26 19:15:04 +00:00
var results []factoid
2012-08-26 19:21:21 +00:00
iter := p.Coll.Find(bson.M{"trigger": strings.ToLower(message)}).Iter()
2012-08-26 19:15:04 +00:00
err := iter.All(&results)
if err != nil {
panic(err)
}
nfacts := len(results)
if nfacts == 0 {
return false, nil
2012-08-26 19:15:04 +00:00
}
fact := results[rand.Intn(nfacts)]
return true, &fact
}
func (p *FactoidPlugin) trigger(message bot.Message) bool {
if len(message.Body) > 4 {
if ok, fact := p.findTrigger(message.Body); ok {
msg := p.Bot.Filter(message, fact.FullText)
if fact.Operator == "action" {
p.Bot.SendAction(message.Channel, msg)
} else {
p.Bot.SendMessage(message.Channel, msg)
}
return true
}
}
return false
2012-08-26 19:15:04 +00:00
}
// Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *FactoidPlugin) Message(message bot.Message) bool {
// This bot does not reply to anything
body := strings.TrimSpace(message.Body)
2012-08-26 19:15:04 +00:00
// This plugin has no business with normal messages
if !message.Command {
// look for any triggers in the db matching this message
return p.trigger(message)
2012-08-26 19:15:04 +00:00
}
action := p.findAction(body)
2012-08-26 19:15:04 +00:00
if action != "" {
parts := strings.SplitN(body, action, 2)
2012-08-26 19:15:04 +00:00
// This could fail if is were the last word or it weren't in the sentence (like no spaces)
if len(parts) != 2 {
return false
}
trigger := strings.TrimSpace(parts[0])
fact := strings.TrimSpace(parts[1])
action := strings.TrimSpace(action)
if len(trigger) == 0 || len(fact) == 0 || len(action) == 0 {
p.Bot.SendMessage(message.Channel, "I don't want to learn that.")
return false
}
2012-08-26 19:15:04 +00:00
strippedaction := strings.Replace(strings.Replace(action, "<", "", 1), ">", "", 1)
if p.learnFact(message, trigger, strippedaction, fact) {
p.Bot.SendMessage(message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name))
} else {
p.Bot.SendMessage(message.Channel, "I already know that.")
}
2012-08-26 19:15:04 +00:00
return true
}
// look for any triggers in the db matching this message
if p.trigger(message) {
2012-08-26 19:15:04 +00:00
return true
}
p.Bot.SendMessage(message.Channel, p.NotFound[rand.Intn(len(p.NotFound))])
2012-08-26 19:15:04 +00:00
return true
}
// LoadData imports any configuration data into the plugin. This is not strictly necessary other
// than the fact that the Plugin interface demands it exist. This may be deprecated at a later
// date.
func (p *FactoidPlugin) LoadData() {
// This bot has no data to load
p.Coll = p.Bot.Db.C("factoid")
rand.Seed(time.Now().Unix())
}
// Help responds to help requests. Every plugin must implement a help function.
func (p *FactoidPlugin) Help(channel string, parts []string) {
2012-08-26 19:29:34 +00:00
p.Bot.SendMessage(channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he <has> $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.")
p.Bot.SendMessage(channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.")
2012-08-26 19:15:04 +00:00
}
// Empty event handler because this plugin does not do anything on event recv
func (p *FactoidPlugin) Event(kind string, message bot.Message) bool {
return false
}