counter: refactor into regex matchers

This commit is contained in:
Chris Sexton 2021-01-31 21:21:19 -05:00 committed by Chris Sexton
parent 9b5d39fdc7
commit 1292eaa564
1 changed files with 329 additions and 295 deletions

View File

@ -20,8 +20,6 @@ import (
// This is a counter plugin to count arbitrary things. // This is a counter plugin to count arbitrary things.
var teaMatcher = regexp.MustCompile("(?i)^([^.]+)\\. [^.]*\\. ([^.]*\\.?)+$")
type CounterPlugin struct { type CounterPlugin struct {
Bot bot.Bot Bot bot.Bot
DB *sqlx.DB DB *sqlx.DB
@ -262,7 +260,20 @@ func New(b bot.Bot) *CounterPlugin {
Bot: b, Bot: b,
DB: b.DB(), DB: b.DB(),
} }
b.Register(cp, bot.Message, cp.message)
b.RegisterRegexCmd(cp, bot.Message, mkAliasRegex, cp.mkAliasCmd)
b.RegisterRegexCmd(cp, bot.Message, rmAliasRegex, cp.rmAliasCmd)
b.RegisterRegexCmd(cp, bot.Message, leaderboardRegex, cp.leaderboardCmd)
b.RegisterRegex(cp, bot.Message, teaRegex, cp.teaMatchCmd)
b.RegisterRegexCmd(cp, bot.Message, resetRegex, cp.resetCmd)
b.RegisterRegexCmd(cp, bot.Message, inspectRegex, cp.inspectCmd)
b.RegisterRegexCmd(cp, bot.Message, clearRegex, cp.clearCmd)
b.RegisterRegexCmd(cp, bot.Message, countRegex, cp.countCmd)
b.RegisterRegex(cp, bot.Message, incrementRegex, cp.incrementCmd)
b.RegisterRegex(cp, bot.Message, decrementRegex, cp.decrementCmd)
b.RegisterRegex(cp, bot.Message, addToRegex, cp.addToCmd)
b.RegisterRegex(cp, bot.Message, removeFromRegex, cp.removeFromCmd)
b.Register(cp, bot.Help, cp.help) b.Register(cp, bot.Help, cp.help)
cp.registerWeb() cp.registerWeb()
@ -273,46 +284,61 @@ func trimUnicode(s string) string {
return strings.Trim(s, string(rune(0xFE0F))) return strings.Trim(s, string(rune(0xFE0F)))
} }
// Message responds to the bot hook on recieving messages. var mkAliasRegex = regexp.MustCompile(`(?i)^mkalias (?P<what>\S+) (?P<to>\S+)$`)
// This function returns true if the plugin responds in a meaningful way to the var rmAliasRegex = regexp.MustCompile(`(?i)^rmalias (?P<what>\S+)$`)
// users message. Otherwise, the function returns false and the bot continues var leaderboardRegex = regexp.MustCompile(`(?i)^leaderboard\s?(?P<what>\S+)?$`)
// execution of other plugins. var teaRegex = regexp.MustCompile("(?i)^([^.]+)\\. [^.]*\\. ([^.]*\\.?)+$")
func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { var resetRegex = regexp.MustCompile(`(?i)^reset me$`)
// This bot does not reply to anything var inspectRegex = regexp.MustCompile(`(?i)^inspect (?P<who>\S+)$`)
nick := message.User.Name var clearRegex = regexp.MustCompile(`(?i)^clear (?P<what>\S+)$`)
channel := message.Channel var countRegex = regexp.MustCompile(`(?i)^count (?P<who>\S+)\s?(?P<what>\S+)?$`)
parts := strings.Fields(message.Body) var incrementRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\+\+$`)
var decrementRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)--$`)
var addToRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s+\+=\s+(?P<amount>\d+)$`)
var removeFromRegex = regexp.MustCompile(`(?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s+-=\s+(?P<amount>\d+)$`)
if len(parts) == 0 { func (p *CounterPlugin) mkAliasCmd(r bot.Request) bool {
return false what := r.Values["what"]
to := r.Values["to"]
if what == "" || to == "" {
p.Bot.Send(r.Conn, bot.Message, fmt.Sprintf("You must provide all fields for an alias: %s", mkAliasRegex))
return true
} }
if _, err := MkAlias(p.DB, what, to); err != nil {
if len(parts) == 3 && strings.ToLower(parts[0]) == "mkalias" {
if _, err := MkAlias(p.DB, parts[1], parts[2]); err != nil {
log.Error().Err(err).Msg("Could not mkalias") log.Error().Err(err).Msg("Could not mkalias")
p.Bot.Send(c, bot.Message, channel, "We're gonna need too much DB space to make an alias for your mom.") p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "We're gonna need too much DB space to make an alias for your mom.")
return true return true
} }
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("Created alias %s -> %s", p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("Created alias %s -> %s",
parts[1], parts[2])) what, to))
return true return true
} else if len(parts) == 2 && strings.ToLower(parts[0]) == "rmalias" { }
if err := RmAlias(p.DB, parts[1]); err != nil {
func (p *CounterPlugin) rmAliasCmd(r bot.Request) bool {
what := r.Values["what"]
if what == "" {
p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "You must specify an alias to remove.")
return true
}
if err := RmAlias(p.DB, what); err != nil {
log.Error().Err(err).Msg("could not RmAlias") log.Error().Err(err).Msg("could not RmAlias")
p.Bot.Send(c, bot.Message, channel, "`sudo rm your mom` => Nope, she's staying with me.") p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "`sudo rm your mom` => Nope, she's staying with me.")
return true return true
} }
p.Bot.Send(c, bot.Message, channel, "`sudo rm your mom`") p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "`sudo rm your mom`")
return true return true
} else if strings.ToLower(parts[0]) == "leaderboard" { }
func (p *CounterPlugin) leaderboardCmd(r bot.Request) bool {
var cmd func() ([]Item, error) var cmd func() ([]Item, error)
itNameTxt := "" itNameTxt := ""
what := r.Values["what"]
if len(parts) == 1 { if what == "" {
cmd = func() ([]Item, error) { return LeaderAll(p.DB) } cmd = func() ([]Item, error) { return LeaderAll(p.DB) }
} else { } else {
itNameTxt = fmt.Sprintf(" for %s", parts[1]) itNameTxt = fmt.Sprintf(" for %s", what)
cmd = func() ([]Item, error) { return Leader(p.DB, parts[1]) } cmd = func() ([]Item, error) { return Leader(p.DB, what) }
} }
its, err := cmd() its, err := cmd()
@ -320,7 +346,8 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
log.Error().Err(err).Msg("Error with leaderboard") log.Error().Err(err).Msg("Error with leaderboard")
return false return false
} else if len(its) == 0 { } else if len(its) == 0 {
return false p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, "There are not enough entries for a leaderboard.")
return true
} }
out := fmt.Sprintf("Leaderboard%s:\n", itNameTxt) out := fmt.Sprintf("Leaderboard%s:\n", itNameTxt)
@ -331,34 +358,41 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
it.Item, it.Item,
) )
} }
p.Bot.Send(c, bot.Message, channel, out) p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, out)
return true return true
} else if match := teaMatcher.MatchString(message.Body); match { }
// check for tea match TTT
return p.checkMatch(c, message) func (p *CounterPlugin) resetCmd(r bot.Request) bool {
} else if message.Command && message.Body == "reset me" { nick := r.Msg.User.Name
channel := r.Msg.Channel
items, err := GetItems(p.DB, strings.ToLower(nick)) items, err := GetItems(p.DB, strings.ToLower(nick))
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Str("nick", nick). Str("nick", nick).
Msg("Error getting items to reset") Msg("Error getting items to reset")
p.Bot.Send(c, bot.Message, channel, "Something is technically wrong with your counters.") p.Bot.Send(r.Conn, bot.Message, channel, "Something is technically wrong with your counters.")
return true return true
} }
log.Debug().Msgf("Items: %+v", items) log.Debug().Msgf("Items: %+v", items)
for _, item := range items { for _, item := range items {
item.Delete() item.Delete()
} }
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick)) p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick))
return true return true
} else if message.Command && parts[0] == "inspect" && len(parts) == 2 { }
var subject string
if parts[1] == "me" { func (p *CounterPlugin) inspectCmd(r bot.Request) bool {
subject = strings.ToLower(nick) var subject string
subject = r.Values["who"]
channel := r.Msg.Channel
c := r.Conn
if subject == "me" {
subject = strings.ToLower(r.Msg.User.Name)
} else { } else {
subject = strings.ToLower(parts[1]) subject = strings.ToLower(subject)
} }
log.Debug(). log.Debug().
@ -397,9 +431,13 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
p.Bot.Send(c, bot.Message, channel, resp) p.Bot.Send(c, bot.Message, channel, resp)
return true return true
} else if message.Command && len(parts) == 2 && parts[0] == "clear" { }
subject := strings.ToLower(nick)
itemName := strings.ToLower(parts[1]) func (p *CounterPlugin) clearCmd(r bot.Request) bool {
subject := strings.ToLower(r.Msg.User.Name)
itemName := strings.ToLower(r.Values["what"])
channel := r.Msg.Channel
c := r.Conn
it, err := GetUserItem(p.DB, subject, itemName) it, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -425,27 +463,27 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
p.Bot.Send(c, bot.Action, channel, fmt.Sprintf("chops a few %s out of his brain", p.Bot.Send(c, bot.Action, channel, fmt.Sprintf("chops a few %s out of his brain",
itemName)) itemName))
return true return true
}
} else if message.Command && parts[0] == "count" { func (p *CounterPlugin) countCmd(r bot.Request) bool {
var subject string var subject string
var itemName string var itemName string
if len(parts) == 3 { if r.Values["what"] == "" && r.Values["who"] == "" {
// report count for parts[1]
subject = strings.ToLower(parts[1])
itemName = strings.ToLower(parts[2])
} else if len(parts) == 2 {
subject = strings.ToLower(nick)
itemName = strings.ToLower(parts[1])
} else {
return false return false
} else if r.Values["what"] != "" {
subject = strings.ToLower(r.Values["who"])
itemName = strings.ToLower(r.Values["what"])
} else {
subject = strings.ToLower(r.Msg.User.Name)
itemName = strings.ToLower(r.Values["who"])
} }
var item Item var item Item
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.", p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("I don't think %s has any %s.",
subject, itemName)) subject, itemName))
return true return true
case err != nil: case err != nil:
@ -457,28 +495,19 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
return true return true
} }
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, p.Bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("%s has %d %s.", subject, item.Count,
itemName)) itemName))
return true return true
} else if len(parts) <= 2 {
if (len(parts) == 2) && (parts[1] == "++" || parts[1] == "--") {
parts = []string{parts[0] + parts[1]}
}
// Need to have at least 3 characters to ++ or --
if len(parts[0]) < 3 {
return false
} }
subject := strings.ToLower(nick) func (p *CounterPlugin) incrementCmd(r bot.Request) bool {
itemName := strings.ToLower(parts[0])[:len(parts[0])-2] subject := r.Msg.User.Name
if r.Values["who"] != "" {
if nameParts := strings.SplitN(itemName, ".", 2); len(nameParts) == 2 { subject = strings.TrimSuffix(r.Values["who"], ".")
subject = nameParts[0]
itemName = nameParts[1]
} }
itemName := r.Values["thing"]
if strings.HasSuffix(parts[0], "++") { channel := r.Msg.Channel
// ++ those fuckers // ++ those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -492,10 +521,18 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
} }
log.Debug().Msgf("About to update item: %#v", item) log.Debug().Msgf("About to update item: %#v", item)
item.UpdateDelta(1) item.UpdateDelta(1)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} else if strings.HasSuffix(parts[0], "--") { }
func (p *CounterPlugin) decrementCmd(r bot.Request) bool {
subject := r.Msg.User.Name
if r.Values["who"] != "" {
subject = strings.TrimSuffix(r.Values["who"], ".")
}
itemName := r.Values["thing"]
channel := r.Msg.Channel
// -- those fuckers // -- those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -508,25 +545,18 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
return false return false
} }
item.UpdateDelta(-1) item.UpdateDelta(-1)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} }
} else if len(parts) == 3 {
// Need to have at least 3 characters to ++ or -- func (p *CounterPlugin) addToCmd(r bot.Request) bool {
if len(parts[0]) < 3 { subject := r.Msg.User.Name
return false if r.Values["who"] != "" {
subject = strings.TrimSuffix(r.Values["who"], ".")
} }
itemName := r.Values["thing"]
subject := strings.ToLower(nick) channel := r.Msg.Channel
itemName := strings.ToLower(parts[0])
if nameParts := strings.SplitN(itemName, ".", 2); len(nameParts) == 2 {
subject = nameParts[0]
itemName = nameParts[1]
}
if parts[1] == "+=" {
// += those fuckers // += those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -538,13 +568,21 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
// Item ain't there, I guess // Item ain't there, I guess
return false return false
} }
n, _ := strconv.Atoi(parts[2]) n, _ := strconv.Atoi(r.Values["amount"])
log.Debug().Msgf("About to update item by %d: %#v", n, item) log.Debug().Msgf("About to update item by %d: %#v", n, item)
item.UpdateDelta(n) item.UpdateDelta(n)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} else if parts[1] == "-=" { }
func (p *CounterPlugin) removeFromCmd(r bot.Request) bool {
subject := r.Msg.User.Name
if r.Values["who"] != "" {
subject = strings.TrimSuffix(r.Values["who"], ".")
}
itemName := r.Values["thing"]
channel := r.Msg.Channel
// -= those fuckers // -= those fuckers
item, err := GetUserItem(p.DB, subject, itemName) item, err := GetUserItem(p.DB, subject, itemName)
if err != nil { if err != nil {
@ -556,17 +594,13 @@ func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Mess
// Item ain't there, I guess // Item ain't there, I guess
return false return false
} }
n, _ := strconv.Atoi(parts[2]) n, _ := strconv.Atoi(r.Values["amount"])
log.Debug().Msgf("About to update item by -%d: %#v", n, item) log.Debug().Msgf("About to update item by -%d: %#v", n, item)
item.UpdateDelta(-n) item.UpdateDelta(-n)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} }
}
return false
}
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *CounterPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { func (p *CounterPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
@ -579,11 +613,11 @@ func (p *CounterPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message
return true return true
} }
func (p *CounterPlugin) checkMatch(c bot.Connector, message msg.Message) bool { func (p *CounterPlugin) teaMatchCmd(r bot.Request) bool {
nick := message.User.Name nick := r.Msg.User.Name
channel := message.Channel channel := r.Msg.Channel
submatches := teaMatcher.FindStringSubmatch(message.Body) submatches := teaRegex.FindStringSubmatch(r.Msg.Body)
if len(submatches) <= 1 { if len(submatches) <= 1 {
return false return false
} }
@ -605,7 +639,7 @@ func (p *CounterPlugin) checkMatch(c bot.Connector, message msg.Message) bool {
delta = -1 delta = -1
} }
item.UpdateDelta(delta) item.UpdateDelta(delta)
p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s... %s has %d %s", p.Bot.Send(r.Conn, bot.Message, channel, fmt.Sprintf("%s... %s has %d %s",
strings.Join(everyDayImShuffling([]string{"bleep", "bloop", "blop"}), "-"), nick, item.Count, itemName)) strings.Join(everyDayImShuffling([]string{"bleep", "bloop", "blop"}), "-"), nick, item.Count, itemName))
return true return true
} }