From 42f7f52bfb6fe2bb0c09ac0f0fcadf01f8713055 Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Mon, 27 May 2019 19:21:53 -0400 Subject: [PATCH] cli: make a new plugin --- .gitignore | 1 + bot/bot.go | 10 +- bot/handlers.go | 42 ++++---- bot/interfaces.go | 9 +- bot/mock.go | 34 +++--- config/config.go | 6 +- connectors/irc/irc.go | 4 +- connectors/slack/slack.go | 4 +- connectors/slackapp/slackApp.go | 4 +- main.go | 2 + plugins/admin/admin.go | 32 +++--- plugins/admin/admin_test.go | 6 +- plugins/babbler/babbler.go | 10 +- plugins/babbler/babbler_test.go | 105 +++++++++--------- plugins/beers/beers.go | 62 +++++------ plugins/beers/beers_test.go | 8 +- plugins/cli/cli.go | 114 ++++++++++++++++++++ plugins/cli/index.html | 137 ++++++++++++++++++++++++ plugins/couldashouldawoulda/csw.go | 4 +- plugins/couldashouldawoulda/csw_test.go | 5 +- plugins/counter/counter.go | 44 ++++---- plugins/counter/counter_test.go | 7 +- plugins/db/db.go | 46 -------- plugins/dice/dice.go | 10 +- plugins/dice/dice_test.go | 7 +- plugins/emojifyme/emojifyme.go | 4 +- plugins/fact/fact_test.go | 7 +- plugins/fact/factoid.go | 94 ++++++++-------- plugins/fact/webTemplates.go | 2 +- plugins/first/first.go | 22 ++-- plugins/inventory/inventory.go | 22 ++-- plugins/leftpad/leftpad.go | 8 +- plugins/leftpad/leftpad_test.go | 5 +- plugins/nerdepedia/nerdepedia.go | 8 +- plugins/nerdepedia/nerdepeida_test.go | 5 +- plugins/picker/picker.go | 16 +-- plugins/picker/picker_test.go | 5 +- plugins/reaction/reaction.go | 28 ++--- plugins/remember/remember.go | 14 +-- plugins/remember/remember_test.go | 3 +- plugins/reminder/reminder.go | 38 +++---- plugins/reminder/reminder_test.go | 9 +- plugins/rpgORdie/rpgORdie.go | 26 ++--- plugins/rpgORdie/rpgORdie_test.go | 2 - plugins/rss/rss.go | 16 +-- plugins/rss/rss_test.go | 5 +- plugins/sisyphus/sisyphus.go | 62 +++++------ plugins/talker/talker.go | 30 +++--- plugins/talker/talker_test.go | 7 +- plugins/tell/tell.go | 6 +- plugins/tldr/tldr.go | 10 +- plugins/tldr/tldr_test.go | 7 +- plugins/twitch/twitch.go | 36 +++---- plugins/twitch/twitch_test.go | 5 +- plugins/your/your.go | 8 +- plugins/your/your_test.go | 5 +- plugins/zork/zork.go | 14 +-- 57 files changed, 744 insertions(+), 498 deletions(-) create mode 100644 plugins/cli/cli.go create mode 100644 plugins/cli/index.html delete mode 100644 plugins/db/db.go diff --git a/.gitignore b/.gitignore index 29c8840..6a15fae 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ Temporary Items util/*/files util/*/files run.sh +.idea diff --git a/bot/bot.go b/bot/bot.go index 8ba3029..e66eda7 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -59,7 +59,7 @@ func New(config *config.Config, connector Connector) Bot { msglog.RunNew(logIn, logOut) users := []user.User{ - user.User{ + { Name: config.Get("Nick", "bot"), }, } @@ -87,6 +87,14 @@ func New(config *config.Config, connector Connector) Bot { return bot } +func (b *bot) DefaultConnector() Connector { + return b.conn +} + +func (b *bot) WhoAmI() string { + return b.me.Name +} + // Config gets the configuration that the bot is using func (b *bot) Config() *config.Config { return b.config diff --git a/bot/handlers.go b/bot/handlers.go index 5dfe12c..0a1a3e9 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -17,7 +17,7 @@ import ( "github.com/velour/catbase/bot/msg" ) -func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool { +func (b *bot) Receive(conn Connector, kind Kind, msg msg.Message, args ...interface{}) bool { log.Debug(). Interface("msg", msg). Msg("Received event") @@ -26,13 +26,13 @@ func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool { // do need to look up user and fix it if kind == Message && strings.HasPrefix(msg.Body, "help") && msg.Command { parts := strings.Fields(strings.ToLower(msg.Body)) - b.checkHelp(msg.Channel, parts) + b.checkHelp(conn, msg.Channel, parts) log.Debug().Msg("Handled a help, returning") goto RET } for _, name := range b.pluginOrdering { - if b.runCallback(b.plugins[name], kind, msg, args...) { + if b.runCallback(conn, b.plugins[name], kind, msg, args...) { goto RET } } @@ -42,10 +42,10 @@ RET: return true } -func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool { +func (b *bot) runCallback(conn Connector, plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool { t := reflect.TypeOf(plugin).String() for _, cb := range b.callbacks[t][evt] { - if cb(evt, message, args...) { + if cb(conn, evt, message, args...) { return true } } @@ -53,8 +53,8 @@ func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ... } // Send a message to the connection -func (b *bot) Send(kind Kind, args ...interface{}) (string, error) { - return b.conn.Send(kind, args...) +func (b *bot) Send(conn Connector, kind Kind, args ...interface{}) (string, error) { + return conn.Send(kind, args...) } func (b *bot) GetEmojiList() map[string]string { @@ -62,38 +62,38 @@ func (b *bot) GetEmojiList() map[string]string { } // Checks to see if the user is asking for help, returns true if so and handles the situation. -func (b *bot) checkHelp(channel string, parts []string) { +func (b *bot) checkHelp(conn Connector, channel string, parts []string) { if len(parts) == 1 { // just print out a list of help topics topics := "Help topics: about variables" - for name, _ := range b.plugins { + for name := range b.plugins { name = strings.Split(strings.TrimPrefix(name, "*"), ".")[0] topics = fmt.Sprintf("%s, %s", topics, name) } - b.Send(Message, channel, topics) + b.Send(conn, Message, channel, topics) } else { // trigger the proper plugin's help response if parts[1] == "about" { - b.Help(channel, parts) + b.Help(conn, channel, parts) return } if parts[1] == "variables" { - b.listVars(channel, parts) + b.listVars(conn, channel, parts) return } for name, plugin := range b.plugins { if strings.HasPrefix(name, "*"+parts[1]) { - if b.runCallback(plugin, Help, msg.Message{Channel: channel}, channel, parts) { + if b.runCallback(conn, plugin, Help, msg.Message{Channel: channel}, channel, parts) { return } else { msg := fmt.Sprintf("I'm sorry, I don't know how to help you with %s.", parts[1]) - b.Send(Message, channel, msg) + b.Send(conn, Message, channel, msg) return } } } msg := fmt.Sprintf("I'm sorry, I don't know what %s is!", strings.Join(parts, " ")) - b.Send(Message, channel, msg) + b.Send(conn, Message, channel, msg) } } @@ -178,7 +178,7 @@ func (b *bot) getVar(varName string) (string, error) { return text, nil } -func (b *bot) listVars(channel string, parts []string) { +func (b *bot) listVars(conn Connector, channel string, parts []string) { var variables []string err := b.DB().Select(&variables, `select name from variables group by name`) if err != nil { @@ -188,18 +188,18 @@ func (b *bot) listVars(channel string, parts []string) { if len(variables) > 0 { msg += ", " + strings.Join(variables, ", ") } - b.Send(Message, channel, msg) + b.Send(conn, Message, channel, msg) } -func (b *bot) Help(channel string, parts []string) { +func (b *bot) Help(conn Connector, channel string, parts []string) { msg := fmt.Sprintf("Hi, I'm based on godeepintir version %s. I'm written in Go, and you "+ "can find my source code on the internet here: "+ "http://github.com/velour/catbase", b.version) - b.Send(Message, channel, msg) + b.Send(conn, Message, channel, msg) } // Send our own musings to the plugins -func (b *bot) selfSaid(channel, message string, action bool) { +func (b *bot) selfSaid(conn Connector, channel, message string, action bool) { msg := msg.Message{ User: &b.me, // hack Channel: channel, @@ -212,7 +212,7 @@ func (b *bot) selfSaid(channel, message string, action bool) { } for _, name := range b.pluginOrdering { - if b.runCallback(b.plugins[name], SelfMessage, msg) { + if b.runCallback(conn, b.plugins[name], SelfMessage, msg) { return } } diff --git a/bot/interfaces.go b/bot/interfaces.go index bc71c6c..fba9396 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -36,7 +36,7 @@ type ImageAttachment struct { } type Kind int -type Callback func(Kind, msg.Message, ...interface{}) bool +type Callback func(Connector, Kind, msg.Message, ...interface{}) bool type CallbackMap map[string]map[Kind][]Callback // Bot interface serves to allow mocking of the actual bot @@ -47,12 +47,14 @@ type Bot interface { DB() *sqlx.DB // Who lists users in a particular channel Who(string) []user.User + // WhoAmI gives a nick for the bot + WhoAmI() string // AddPlugin registers a new plugin handler AddPlugin(Plugin) // First arg should be one of bot.Message/Reply/Action/etc - Send(Kind, ...interface{}) (string, error) + Send(Connector, Kind, ...interface{}) (string, error) // First arg should be one of bot.Message/Reply/Action/etc - Receive(Kind, msg.Message, ...interface{}) bool + Receive(Connector, Kind, msg.Message, ...interface{}) bool // Register a callback Register(Plugin, Kind, Callback) @@ -63,6 +65,7 @@ type Bot interface { GetEmojiList() map[string]string RegisterFilter(string, func(string) string) RegisterWeb(string, string) + DefaultConnector() Connector } // Connector represents a server connection to a chat service diff --git a/bot/mock.go b/bot/mock.go index 6f11c12..6f67c62 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -27,10 +27,12 @@ type MockBot struct { Reactions []string } -func (mb *MockBot) Config() *config.Config { return mb.Cfg } -func (mb *MockBot) DB() *sqlx.DB { return mb.Cfg.DB } -func (mb *MockBot) Who(string) []user.User { return []user.User{} } -func (mb *MockBot) Send(kind Kind, args ...interface{}) (string, error) { +func (mb *MockBot) Config() *config.Config { return mb.Cfg } +func (mb *MockBot) DB() *sqlx.DB { return mb.Cfg.DB } +func (mb *MockBot) Who(string) []user.User { return []user.User{} } +func (mb *MockBot) WhoAmI() string { return "tester" } +func (mb *MockBot) DefaultConnector() Connector { return nil } +func (mb *MockBot) Send(c Connector, kind Kind, args ...interface{}) (string, error) { switch kind { case Message: mb.Messages = append(mb.Messages, args[1].(string)) @@ -40,27 +42,29 @@ func (mb *MockBot) Send(kind Kind, args ...interface{}) (string, error) { return fmt.Sprintf("a-%d", len(mb.Actions)-1), nil case Edit: ch, m, id := args[0].(string), args[1].(string), args[2].(string) - return mb.edit(ch, m, id) + return mb.edit(c, ch, m, id) case Reaction: ch, re, msg := args[0].(string), args[1].(string), args[2].(msg.Message) - return mb.react(ch, re, msg) + return mb.react(c, ch, re, msg) } return "ERR", fmt.Errorf("Mesasge type unhandled") } -func (mb *MockBot) AddPlugin(f Plugin) {} -func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {} -func (mb *MockBot) RegisterWeb(_, _ string) {} -func (mb *MockBot) Receive(kind Kind, msg msg.Message, args ...interface{}) bool { return false } -func (mb *MockBot) Filter(msg msg.Message, s string) string { return s } -func (mb *MockBot) LastMessage(ch string) (msg.Message, error) { return msg.Message{}, nil } -func (mb *MockBot) CheckAdmin(nick string) bool { return false } +func (mb *MockBot) AddPlugin(f Plugin) {} +func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {} +func (mb *MockBot) RegisterWeb(_, _ string) {} +func (mb *MockBot) Receive(c Connector, kind Kind, msg msg.Message, args ...interface{}) bool { + return false +} +func (mb *MockBot) Filter(msg msg.Message, s string) string { return s } +func (mb *MockBot) LastMessage(ch string) (msg.Message, error) { return msg.Message{}, nil } +func (mb *MockBot) CheckAdmin(nick string) bool { return false } -func (mb *MockBot) react(channel, reaction string, message msg.Message) (string, error) { +func (mb *MockBot) react(c Connector, channel, reaction string, message msg.Message) (string, error) { mb.Reactions = append(mb.Reactions, reaction) return "", nil } -func (mb *MockBot) edit(channel, newMessage, identifier string) (string, error) { +func (mb *MockBot) edit(c Connector, channel, newMessage, identifier string) (string, error) { isMessage := identifier[0] == 'm' if !isMessage && identifier[0] != 'a' { err := fmt.Errorf("failed to parse identifier: %s", identifier) diff --git a/config/config.go b/config/config.go index 3431a8f..ee767d2 100644 --- a/config/config.go +++ b/config/config.go @@ -11,7 +11,7 @@ import ( "strings" "github.com/jmoiron/sqlx" - sqlite3 "github.com/mattn/go-sqlite3" + "github.com/mattn/go-sqlite3" "github.com/rs/zerolog/log" ) @@ -98,8 +98,8 @@ func (c *Config) GetArray(key string, fallback []string) []string { // Note, this is always a string. Use the SetArray for an array helper func (c *Config) Set(key, value string) error { key = strings.ToLower(key) - q := (`insert into config (key,value) values (?, ?) - on conflict(key) do update set value=?;`) + q := `insert into config (key,value) values (?, ?) + on conflict(key) do update set value=?;` tx, err := c.Begin() if err != nil { return err diff --git a/connectors/irc/irc.go b/connectors/irc/irc.go index b57bdd7..cead610 100644 --- a/connectors/irc/irc.go +++ b/connectors/irc/irc.go @@ -248,10 +248,10 @@ func (i *Irc) handleMsg(msg irc.Msg) { fallthrough case irc.RPL_ENDOFWHO: - i.event(bot.Event, botMsg) + i.event(i, bot.Event, botMsg) case irc.PRIVMSG: - i.event(bot.Message, botMsg) + i.event(i, bot.Message, botMsg) case irc.QUIT: os.Exit(1) diff --git a/connectors/slack/slack.go b/connectors/slack/slack.go index 16076a9..bb1ad3d 100644 --- a/connectors/slack/slack.go +++ b/connectors/slack/slack.go @@ -455,11 +455,11 @@ func (s *Slack) Serve() error { log.Debug().Msgf("Ignoring message: %+v\nlastRecieved: %v msg: %v", msg.ID, s.lastRecieved, m.Time) } else { s.lastRecieved = m.Time - s.event(bot.Message, m) + s.event(s, bot.Message, m) } } else if msg.ThreadTs != "" { //we're throwing away some information here by not parsing the correct reply object type, but that's okay - s.event(bot.Reply, s.buildLightReplyMessage(msg), msg.ThreadTs) + s.event(s, bot.Reply, s.buildLightReplyMessage(msg), msg.ThreadTs) } else { log.Debug().Msgf("THAT MESSAGE WAS HIDDEN: %+v", msg.ID) } diff --git a/connectors/slackapp/slackApp.go b/connectors/slackapp/slackApp.go index 52e3e31..d45708a 100644 --- a/connectors/slackapp/slackApp.go +++ b/connectors/slackapp/slackApp.go @@ -167,11 +167,11 @@ func (s *SlackApp) msgReceivd(msg *slackevents.MessageEvent) { Msg("Ignoring message") } else { s.lastRecieved = m.Time - s.event(bot.Message, m) + s.event(s, bot.Message, m) } } else if msg.ThreadTimeStamp != "" { //we're throwing away some information here by not parsing the correct reply object type, but that's okay - s.event(bot.Reply, s.buildMessage(msg), msg.ThreadTimeStamp) + s.event(s, bot.Reply, s.buildMessage(msg), msg.ThreadTimeStamp) } else { log.Debug(). Str("text", msg.Text). diff --git a/main.go b/main.go index ea9e10a..6837a05 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ package main import ( "flag" + "github.com/velour/catbase/plugins/cli" "math/rand" "net/http" "os" @@ -121,6 +122,7 @@ func main() { b.AddPlugin(couldashouldawoulda.New(b)) b.AddPlugin(nerdepedia.New(b)) b.AddPlugin(tldr.New(b)) + b.AddPlugin(cli.New(b)) // catches anything left, will always return true b.AddPlugin(fact.New(b)) diff --git a/plugins/admin/admin.go b/plugins/admin/admin.go index f7a38a2..a050e97 100644 --- a/plugins/admin/admin.go +++ b/plugins/admin/admin.go @@ -47,7 +47,7 @@ var forbiddenKeys = map[string]bool{ // 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 *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *AdminPlugin) message(conn bot.Connector, k bot.Kind, message msg.Message, args ...interface{}) bool { body := message.Body if p.quiet { @@ -55,7 +55,7 @@ func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface } if len(body) > 0 && body[0] == '$' { - return p.handleVariables(message) + return p.handleVariables(conn, message) } if !message.Command { @@ -65,7 +65,7 @@ func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface if strings.ToLower(body) == "shut up" { dur := time.Duration(p.cfg.GetInt("quietDuration", 5)) * time.Minute log.Info().Msgf("Going to sleep for %v, %v", dur, time.Now().Add(dur)) - p.Bot.Send(bot.Message, message.Channel, "Okay. I'll be back later.") + p.Bot.Send(conn, bot.Message, message.Channel, "Okay. I'll be back later.") p.quiet = true go func() { select { @@ -79,36 +79,36 @@ func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface parts := strings.Split(body, " ") if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] { - p.Bot.Send(bot.Message, message.Channel, "You cannot access that key") + p.Bot.Send(conn, bot.Message, message.Channel, "You cannot access that key") return true } else if parts[0] == "set" && len(parts) > 2 { p.cfg.Set(parts[1], strings.Join(parts[2:], " ")) - p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("Set %s", parts[1])) + p.Bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("Set %s", parts[1])) return true } if parts[0] == "get" && len(parts) == 2 && forbiddenKeys[parts[1]] { - p.Bot.Send(bot.Message, message.Channel, "You cannot access that key") + p.Bot.Send(conn, bot.Message, message.Channel, "You cannot access that key") return true } else if parts[0] == "get" && len(parts) == 2 { v := p.cfg.Get(parts[1], "") - p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("%s: %s", parts[1], v)) + p.Bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("%s: %s", parts[1], v)) return true } return false } -func (p *AdminPlugin) handleVariables(message msg.Message) bool { +func (p *AdminPlugin) handleVariables(conn bot.Connector, message msg.Message) bool { if parts := strings.SplitN(message.Body, "!=", 2); len(parts) == 2 { variable := strings.ToLower(strings.TrimSpace(parts[0])) value := strings.TrimSpace(parts[1]) _, err := p.db.Exec(`delete from variables where name=? and value=?`, variable, value) if err != nil { - p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.") + p.Bot.Send(conn, bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.") log.Error().Err(err) } else { - p.Bot.Send(bot.Message, message.Channel, "Removed.") + p.Bot.Send(conn, bot.Message, message.Channel, "Removed.") } return true @@ -126,27 +126,27 @@ func (p *AdminPlugin) handleVariables(message msg.Message) bool { row := p.db.QueryRow(`select count(*) from variables where value = ?`, variable, value) err := row.Scan(&count) if err != nil { - p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.") + p.Bot.Send(conn, bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.") log.Error().Err(err) return true } if count > 0 { - p.Bot.Send(bot.Message, message.Channel, "I've already got that one.") + p.Bot.Send(conn, bot.Message, message.Channel, "I've already got that one.") } else { _, err := p.db.Exec(`INSERT INTO variables (name, value) VALUES (?, ?)`, variable, value) if err != nil { - p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.") + p.Bot.Send(conn, bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.") log.Error().Err(err) return true } - p.Bot.Send(bot.Message, message.Channel, "Added.") + p.Bot.Send(conn, bot.Message, message.Channel, "Added.") } return true } // Help responds to help requests. Every plugin must implement a help function. -func (p *AdminPlugin) help(kind bot.Kind, m msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, m.Channel, "This does super secret things that you're not allowed to know about.") +func (p *AdminPlugin) help(conn bot.Connector, kind bot.Kind, m msg.Message, args ...interface{}) bool { + p.Bot.Send(conn, bot.Message, m.Channel, "This does super secret things that you're not allowed to know about.") return true } diff --git a/plugins/admin/admin_test.go b/plugins/admin/admin_test.go index 069b21d..917b5b9 100644 --- a/plugins/admin/admin_test.go +++ b/plugins/admin/admin_test.go @@ -1,6 +1,7 @@ package admin import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -22,12 +23,13 @@ func setup(t *testing.T) (*AdminPlugin, *bot.MockBot) { return a, mb } -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + c := cli.CliPlugin{} + return &c, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/babbler/babbler.go b/plugins/babbler/babbler.go index 2c8311f..2b3854e 100644 --- a/plugins/babbler/babbler.go +++ b/plugins/babbler/babbler.go @@ -101,7 +101,7 @@ func New(b bot.Bot) *BabblerPlugin { return plugin } -func (p *BabblerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *BabblerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { lowercase := strings.ToLower(message.Body) tokens := strings.Fields(lowercase) numTokens := len(tokens) @@ -143,12 +143,12 @@ func (p *BabblerPlugin) message(kind bot.Kind, message msg.Message, args ...inte } if saidSomething { - p.Bot.Send(bot.Message, message.Channel, saidWhat) + p.Bot.Send(c, bot.Message, message.Channel, saidWhat) } return saidSomething } -func (p *BabblerPlugin) help(kind bot.Kind, msg msg.Message, args ...interface{}) bool { +func (p *BabblerPlugin) help(c bot.Connector, kind bot.Kind, msg msg.Message, args ...interface{}) bool { commands := []string{ "initialize babbler for seabass", "merge babbler drseabass into seabass", @@ -157,7 +157,7 @@ func (p *BabblerPlugin) help(kind bot.Kind, msg msg.Message, args ...interface{} "seabass says-middle-out ...", "seabass says-bridge ... | ...", } - p.Bot.Send(bot.Message, msg.Channel, strings.Join(commands, "\n\n")) + p.Bot.Send(c, bot.Message, msg.Channel, strings.Join(commands, "\n\n")) return true } @@ -851,7 +851,7 @@ func (p *BabblerPlugin) babbleSeedBookends(babblerName string, start, end []stri previous *searchNode } - open := []*searchNode{&searchNode{startWordNode.NodeId, nil}} + open := []*searchNode{{startWordNode.NodeId, nil}} closed := map[int64]*searchNode{startWordNode.NodeId: open[0]} goalNodeId := int64(-1) diff --git a/plugins/babbler/babbler_test.go b/plugins/babbler/babbler_test.go index a569e0d..0239396 100644 --- a/plugins/babbler/babbler_test.go +++ b/plugins/babbler/babbler_test.go @@ -3,6 +3,7 @@ package babbler import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,13 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { + c := &cli.CliPlugin{} isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return c, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, @@ -64,13 +66,13 @@ func TestBabbler(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is a message") + c, k, seabass := makeMessage("This is a message") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) seabass.Body = "This is another message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = "This is a long message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -82,13 +84,13 @@ func TestBabblerSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is a message") + c, k, seabass := makeMessage("This is a message") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) seabass.Body = "This is another message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = "This is a long message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says long")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -99,13 +101,13 @@ func TestBabblerMultiSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is a message") + c, k, seabass := makeMessage("This is a message") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) seabass.Body = "This is another message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = "This is a long message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says This is a long")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -116,13 +118,13 @@ func TestBabblerMultiSeed2(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is a message") + c, k, seabass := makeMessage("This is a message") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) seabass.Body = "This is another message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = "This is a long message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says is a long")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -133,13 +135,13 @@ func TestBabblerBadSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is a message") + c, k, seabass := makeMessage("This is a message") seabass.User = &user.User{Name: "seabass"} - bp.message(k, seabass) + bp.message(c, k, seabass) seabass.Body = "This is another message" - bp.message(k, seabass) + bp.message(c, k, seabass) seabass.Body = "This is a long message" - bp.message(k, seabass) + bp.message(c, k, seabass) bp.message(makeMessage("!seabass says noooo this is bad")) assert.Len(t, mb.Messages, 1) assert.Contains(t, mb.Messages[0], "seabass never said 'noooo this is bad'") @@ -149,13 +151,13 @@ func TestBabblerBadSeed2(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is a message") + c, k, seabass := makeMessage("This is a message") seabass.User = &user.User{Name: "seabass"} - bp.message(k, seabass) + bp.message(c, k, seabass) seabass.Body = "This is another message" - bp.message(k, seabass) + bp.message(c, k, seabass) seabass.Body = "This is a long message" - bp.message(k, seabass) + bp.message(c, k, seabass) bp.message(makeMessage("!seabass says This is a really")) assert.Len(t, mb.Messages, 1) assert.Contains(t, mb.Messages[0], "seabass never said 'this is a really'") @@ -165,13 +167,13 @@ func TestBabblerSuffixSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is message one") + c, k, seabass := makeMessage("This is message one") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) seabass.Body = "It's easier to test with unique messages" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = "hi there" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-tail message one")) res = bp.message(makeMessage("!seabass says-tail with unique")) assert.Len(t, mb.Messages, 2) @@ -184,13 +186,13 @@ func TestBabblerBadSuffixSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("This is message one") + c, k, seabass := makeMessage("This is message one") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) seabass.Body = "It's easier to test with unique messages" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = "hi there" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-tail anything true")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -201,9 +203,9 @@ func TestBabblerBookendSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("It's easier to test with unique messages") + c, k, seabass := makeMessage("It's easier to test with unique messages") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-bridge It's easier | unique messages")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -214,9 +216,9 @@ func TestBabblerBookendSeedShort(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("It's easier to test with unique messages") + c, k, seabass := makeMessage("It's easier to test with unique messages") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-bridge It's easier to test with | unique messages")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -227,9 +229,9 @@ func TestBabblerBadBookendSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("It's easier to test with unique messages") + c, k, seabass := makeMessage("It's easier to test with unique messages") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-bridge It's easier | not unique messages")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -240,9 +242,9 @@ func TestBabblerMiddleOutSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("It's easier to test with unique messages") + c, k, seabass := makeMessage("It's easier to test with unique messages") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-middle-out test with")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -253,9 +255,9 @@ func TestBabblerBadMiddleOutSeed(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("It's easier to test with unique messages") + c, k, seabass := makeMessage("It's easier to test with unique messages") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) res = bp.message(makeMessage("!seabass says-middle-out anything true")) assert.Len(t, mb.Messages, 1) assert.True(t, res) @@ -266,8 +268,8 @@ func TestBabblerBatch(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage("batch learn for seabass This is a message! This is another message. This is not a long message? This is not a message! This is not another message. This is a long message?") - res := bp.message(k, seabass) + c, k, seabass := makeMessage("batch learn for seabass This is a message! This is another message. This is not a long message? This is not a message! This is not another message. This is a long message?") + res := bp.message(c, k, seabass) assert.Len(t, mb.Messages, 1) res = bp.message(makeMessage("!seabass says")) assert.Len(t, mb.Messages, 2) @@ -281,16 +283,16 @@ func TestBabblerMerge(t *testing.T) { bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - k, seabass := makeMessage(" This is a message") + c, k, seabass := makeMessage(" This is a message") seabass.User = &user.User{Name: "seabass"} - res := bp.message(k, seabass) + res := bp.message(c, k, seabass) assert.Len(t, mb.Messages, 0) seabass.Body = " This is another message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) seabass.Body = " This is a long message" - res = bp.message(k, seabass) + res = bp.message(c, k, seabass) res = bp.message(makeMessage("!merge babbler seabass into seabass2")) assert.True(t, res) @@ -309,6 +311,7 @@ func TestHelp(t *testing.T) { mb := bot.NewMockBot() bp := newBabblerPlugin(mb) assert.NotNil(t, bp) - bp.help(bot.Help, msg.Message{Channel: "channel"}, []string{}) + c := &cli.CliPlugin{} + bp.help(c, bot.Help, msg.Message{Channel: "channel"}, []string{}) assert.Len(t, mb.Messages, 1) } diff --git a/plugins/beers/beers.go b/plugins/beers/beers.go index a654c6a..8b818fb 100644 --- a/plugins/beers/beers.go +++ b/plugins/beers/beers.go @@ -53,7 +53,7 @@ func New(b bot.Bot) *BeersPlugin { db: b.DB(), } for _, channel := range b.Config().GetArray("Untappd.Channels", []string{}) { - go p.untappdLoop(channel) + go p.untappdLoop(b.DefaultConnector(), channel) } b.Register(p, bot.Message, p.message) b.Register(p, bot.Help, p.help) @@ -63,7 +63,7 @@ func New(b bot.Bot) *BeersPlugin { // 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 *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *BeersPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { parts := strings.Fields(message.Body) if len(parts) == 0 { @@ -83,49 +83,49 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf count, err := strconv.Atoi(parts[2]) if err != nil { // if it's not a number, maybe it's a nick! - p.Bot.Send(bot.Message, channel, "Sorry, that didn't make any sense.") + p.Bot.Send(c, bot.Message, channel, "Sorry, that didn't make any sense.") } if count < 0 { // you can't be negative msg := fmt.Sprintf("Sorry %s, you can't have negative beers!", nick) - p.Bot.Send(bot.Message, channel, msg) + p.Bot.Send(c, bot.Message, channel, msg) return true } if parts[1] == "+=" { p.addBeers(nick, count) - p.randomReply(channel) + p.randomReply(c, channel) } else if parts[1] == "=" { if count == 0 { - p.puke(nick, channel) + p.puke(c, nick, channel) } else { p.setBeers(nick, count) - p.randomReply(channel) + p.randomReply(c, channel) } } else { - p.Bot.Send(bot.Message, channel, "I don't know your math.") + p.Bot.Send(c, bot.Message, channel, "I don't know your math.") } } else if len(parts) == 2 { if p.doIKnow(parts[1]) { - p.reportCount(parts[1], channel, false) + p.reportCount(c, parts[1], channel, false) } else { msg := fmt.Sprintf("Sorry, I don't know %s.", parts[1]) - p.Bot.Send(bot.Message, channel, msg) + p.Bot.Send(c, bot.Message, channel, msg) } } else if len(parts) == 1 { - p.reportCount(nick, channel, true) + p.reportCount(c, nick, channel, true) } // no matter what, if we're in here, then we've responded return true } else if parts[0] == "puke" { - p.puke(nick, channel) + p.puke(c, nick, channel) return true } if message.Command && parts[0] == "imbibe" { p.addBeers(nick, 1) - p.randomReply(channel) + p.randomReply(c, channel) return true } @@ -134,7 +134,7 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf channel := message.Channel if len(parts) < 2 { - p.Bot.Send(bot.Message, channel, "You must also provide a user name.") + p.Bot.Send(c, bot.Message, channel, "You must also provide a user name.") } else if len(parts) == 3 { chanNick = parts[2] } else if len(parts) == 4 { @@ -159,7 +159,7 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf log.Error().Err(err).Msgf("Error registering untappd") } if count > 0 { - p.Bot.Send(bot.Message, channel, "I'm already watching you.") + p.Bot.Send(c, bot.Message, channel, "I'm already watching you.") return true } _, err = p.db.Exec(`insert into untappd ( @@ -175,13 +175,13 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf ) if err != nil { log.Error().Err(err).Msgf("Error registering untappd") - p.Bot.Send(bot.Message, channel, "I can't see.") + p.Bot.Send(c, bot.Message, channel, "I can't see.") return true } - p.Bot.Send(bot.Message, channel, "I'll be watching you.") + p.Bot.Send(c, bot.Message, channel, "I'll be watching you.") - p.checkUntappd(channel) + p.checkUntappd(c, channel) return true } @@ -190,7 +190,7 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf log.Info(). Str("user", message.User.Name). Msgf("Checking untappd at request of user.") - p.checkUntappd(channel) + p.checkUntappd(c, channel) return true } @@ -198,11 +198,11 @@ func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interf } // Help responds to help requests. Every plugin must implement a help function. -func (p *BeersPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *BeersPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { msg := "Beers: imbibe by using either beers +=,=,++ or with the !imbibe/drink " + "commands. I'll keep a count of how many beers you've had and then if you want " + "to reset, just !puke it all up!" - p.Bot.Send(bot.Message, message.Channel, msg) + p.Bot.Send(c, bot.Message, message.Channel, msg) return true } @@ -232,7 +232,7 @@ func (p *BeersPlugin) getBeers(nick string) int { return ub.Count } -func (p *BeersPlugin) reportCount(nick, channel string, himself bool) { +func (p *BeersPlugin) reportCount(c bot.Connector, nick, channel string, himself bool) { beers := p.getBeers(nick) msg := fmt.Sprintf("%s has had %d beers so far.", nick, beers) if himself { @@ -242,13 +242,13 @@ func (p *BeersPlugin) reportCount(nick, channel string, himself bool) { msg = fmt.Sprintf("You've had %d beers so far, %s.", beers, nick) } } - p.Bot.Send(bot.Message, channel, msg) + p.Bot.Send(c, bot.Message, channel, msg) } -func (p *BeersPlugin) puke(user string, channel string) { +func (p *BeersPlugin) puke(c bot.Connector, user string, channel string) { p.setBeers(user, 0) msg := fmt.Sprintf("Ohhhhhh, and a reversal of fortune for %s!", user) - p.Bot.Send(bot.Message, channel, msg) + p.Bot.Send(c, bot.Message, channel, msg) } func (p *BeersPlugin) doIKnow(nick string) bool { @@ -261,9 +261,9 @@ func (p *BeersPlugin) doIKnow(nick string) bool { } // Sends random affirmation to the channel. This could be better (with a datastore for sayings) -func (p *BeersPlugin) randomReply(channel string) { +func (p *BeersPlugin) randomReply(c bot.Connector, channel string) { replies := []string{"ZIGGY! ZAGGY!", "HIC!", "Stay thirsty, my friend!"} - p.Bot.Send(bot.Message, channel, replies[rand.Intn(len(replies))]) + p.Bot.Send(c, bot.Message, channel, replies[rand.Intn(len(replies))]) } type checkin struct { @@ -343,7 +343,7 @@ func (p *BeersPlugin) pullUntappd() ([]checkin, error) { return beers.Response.Checkins.Items, nil } -func (p *BeersPlugin) checkUntappd(channel string) { +func (p *BeersPlugin) checkUntappd(c bot.Connector, channel string) { token := p.Bot.Config().Get("Untappd.Token", "NONE") if token == "NONE" { log.Info(). @@ -434,11 +434,11 @@ func (p *BeersPlugin) checkUntappd(channel string) { Int("checkin_id", checkin.Checkin_id). Str("msg", msg). Msg("checkin") - p.Bot.Send(bot.Message, args...) + p.Bot.Send(c, bot.Message, args...) } } -func (p *BeersPlugin) untappdLoop(channel string) { +func (p *BeersPlugin) untappdLoop(c bot.Connector, channel string) { frequency := p.Bot.Config().GetInt("Untappd.Freq", 120) if frequency == 0 { return @@ -448,6 +448,6 @@ func (p *BeersPlugin) untappdLoop(channel string) { for { time.Sleep(time.Duration(frequency) * time.Second) - p.checkUntappd(channel) + p.checkUntappd(c, channel) } } diff --git a/plugins/beers/beers_test.go b/plugins/beers/beers_test.go index 4fa07b1..d2c3ba2 100644 --- a/plugins/beers/beers_test.go +++ b/plugins/beers/beers_test.go @@ -3,6 +3,7 @@ package beers import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -13,12 +14,13 @@ import ( "github.com/velour/catbase/plugins/counter" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + c := &cli.CliPlugin{} + return c, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, @@ -121,6 +123,6 @@ func TestBeersReport(t *testing.T) { func TestHelp(t *testing.T) { b, mb := makeBeersPlugin(t) - b.help(bot.Help, msg.Message{Channel: "channel"}, []string{}) + b.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{}) assert.Len(t, mb.Messages, 1) } diff --git a/plugins/cli/cli.go b/plugins/cli/cli.go new file mode 100644 index 0000000..d46357b --- /dev/null +++ b/plugins/cli/cli.go @@ -0,0 +1,114 @@ +// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors. + +package cli + +import ( + "encoding/json" + "fmt" + "github.com/jmoiron/sqlx" + "github.com/rs/zerolog/log" + "github.com/velour/catbase/bot" + "github.com/velour/catbase/bot/msg" + "github.com/velour/catbase/bot/user" + "io/ioutil" + "net/http" + "time" +) + +type CliPlugin struct { + bot bot.Bot + db *sqlx.DB + cache string + counter int +} + +func New(b bot.Bot) *CliPlugin { + cp := &CliPlugin{ + bot: b, + } + cp.registerWeb() + return cp +} + +func (p *CliPlugin) registerWeb() { + http.HandleFunc("/cli/api", p.handleWebAPI) + http.HandleFunc("/cli", p.handleWeb) + p.bot.RegisterWeb("/cli", "CLI") +} + +func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + fmt.Fprintf(w, "Incorrect HTTP method") + return + } + info := struct { + User string `json:"user"` + Payload string `json:"payload"` + }{} + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&info) + if err != nil { + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + log.Debug(). + Interface("postbody", info). + Msg("Got a POST") + + p.bot.Receive(p, bot.Message, msg.Message{ + User: &user.User{ + ID: info.User, + Name: info.User, + Admin: false, + }, + Channel: "web", + Body: info.Payload, + Raw: info.Payload, + Command: true, + Time: time.Now(), + }) + + info.User = p.bot.WhoAmI() + info.Payload = p.cache + p.cache = "" + + data, err := json.Marshal(info) + if err != nil { + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + w.Write(data) +} + +func (p *CliPlugin) handleWeb(w http.ResponseWriter, r *http.Request) { + f, err := ioutil.ReadFile("plugins/cli/index.html") + if err != nil { + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + w.Write(f) +} + +// Completing the Connector interface, but will not actually be a connector +func (p *CliPlugin) RegisterEvent(cb bot.Callback) {} +func (p *CliPlugin) Send(kind bot.Kind, args ...interface{}) (string, error) { + switch kind { + case bot.Message: + fallthrough + case bot.Action: + fallthrough + case bot.Reply: + fallthrough + case bot.Reaction: + p.cache += args[1].(string) + "\n" + } + id := fmt.Sprintf("%d", p.counter) + p.counter++ + return id, nil +} +func (p *CliPlugin) GetEmojiList() map[string]string { return nil } +func (p *CliPlugin) Serve() error { return nil } +func (p *CliPlugin) Who(s string) []string { return nil } diff --git a/plugins/cli/index.html b/plugins/cli/index.html new file mode 100644 index 0000000..36fd8c4 --- /dev/null +++ b/plugins/cli/index.html @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + CLI + + + +
+

CLI

+ + {{ err }} + + + + + + + + + + + + + + + + + + + + Send + + + + +
+ + + + diff --git a/plugins/couldashouldawoulda/csw.go b/plugins/couldashouldawoulda/csw.go index 0052a5e..c424fba 100644 --- a/plugins/couldashouldawoulda/csw.go +++ b/plugins/couldashouldawoulda/csw.go @@ -25,7 +25,7 @@ func New(b bot.Bot) *CSWPlugin { return csw } -func (p *CSWPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *CSWPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if !message.Command { return false } @@ -65,7 +65,7 @@ func (p *CSWPlugin) message(kind bot.Kind, message msg.Message, args ...interfac } } - p.Bot.Send(bot.Message, message.Channel, responses[rand.Intn(len(responses))]) + p.Bot.Send(c, bot.Message, message.Channel, responses[rand.Intn(len(responses))]) return true } diff --git a/plugins/couldashouldawoulda/csw_test.go b/plugins/couldashouldawoulda/csw_test.go index de60dc9..e647ede 100644 --- a/plugins/couldashouldawoulda/csw_test.go +++ b/plugins/couldashouldawoulda/csw_test.go @@ -3,6 +3,7 @@ package couldashouldawoulda import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/counter/counter.go b/plugins/counter/counter.go index 13edb6f..ea3a181 100644 --- a/plugins/counter/counter.go +++ b/plugins/counter/counter.go @@ -225,7 +225,7 @@ func New(b bot.Bot) *CounterPlugin { // 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 *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *CounterPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { // This bot does not reply to anything nick := message.User.Name channel := message.Channel @@ -240,7 +240,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte log.Error().Err(err) return false } - p.Bot.Send(bot.Message, channel, fmt.Sprintf("Created alias %s -> %s", + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("Created alias %s -> %s", parts[1], parts[2])) return true } else if strings.ToLower(parts[0]) == "leaderboard" { @@ -270,11 +270,11 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte it.Item, ) } - p.Bot.Send(bot.Message, channel, out) + p.Bot.Send(c, bot.Message, channel, out) return true } else if match := teaMatcher.MatchString(message.Body); match { // check for tea match TTT - return p.checkMatch(message) + return p.checkMatch(c, message) } else if message.Command && message.Body == "reset me" { items, err := GetItems(p.DB, strings.ToLower(nick)) if err != nil { @@ -282,14 +282,14 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte Err(err). Str("nick", nick). Msg("Error getting items to reset") - p.Bot.Send(bot.Message, channel, "Something is technically wrong with your counters.") + p.Bot.Send(c, bot.Message, channel, "Something is technically wrong with your counters.") return true } log.Debug().Msgf("Items: %+v", items) for _, item := range items { item.Delete() } - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick)) + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick)) return true } else if message.Command && parts[0] == "inspect" && len(parts) == 2 { var subject string @@ -310,7 +310,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte Err(err). Str("subject", subject). Msg("Error retrieving items") - p.Bot.Send(bot.Message, channel, "Something went wrong finding that counter;") + p.Bot.Send(c, bot.Message, channel, "Something went wrong finding that counter;") return true } @@ -330,11 +330,11 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte resp += "." if count == 0 { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has no counters.", subject)) + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has no counters.", subject)) return true } - p.Bot.Send(bot.Message, channel, resp) + p.Bot.Send(c, bot.Message, channel, resp) return true } else if message.Command && len(parts) == 2 && parts[0] == "clear" { subject := strings.ToLower(nick) @@ -347,7 +347,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte Str("subject", subject). Str("itemName", itemName). Msg("Error getting item to remove") - p.Bot.Send(bot.Message, channel, "Something went wrong removing that counter;") + p.Bot.Send(c, bot.Message, channel, "Something went wrong removing that counter;") return true } err = it.Delete() @@ -357,11 +357,11 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte Str("subject", subject). Str("itemName", itemName). Msg("Error removing item") - p.Bot.Send(bot.Message, channel, "Something went wrong removing that counter;") + p.Bot.Send(c, bot.Message, channel, "Something went wrong removing that counter;") return true } - p.Bot.Send(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)) return true @@ -384,7 +384,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte item, err := GetItem(p.DB, subject, itemName) switch { case err == sql.ErrNoRows: - p.Bot.Send(bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.", + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.", subject, itemName)) return true case err != nil: @@ -396,7 +396,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte return true } - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, itemName)) return true @@ -431,7 +431,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte } log.Debug().Msgf("About to update item: %#v", item) item.UpdateDelta(1) - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true } else if strings.HasSuffix(parts[0], "--") { @@ -447,7 +447,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte return false } item.UpdateDelta(-1) - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true } @@ -480,7 +480,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte n, _ := strconv.Atoi(parts[2]) log.Debug().Msgf("About to update item by %d: %#v", n, item) item.UpdateDelta(n) - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true } else if parts[1] == "-=" { @@ -498,7 +498,7 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte n, _ := strconv.Atoi(parts[2]) log.Debug().Msgf("About to update item by -%d: %#v", n, item) item.UpdateDelta(-n) - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, item.Item)) return true } @@ -508,15 +508,15 @@ func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...inte } // Help responds to help requests. Every plugin must implement a help function. -func (p *CounterPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "You can set counters incrementally by using "+ +func (p *CounterPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.Bot.Send(c, bot.Message, message.Channel, "You can set counters incrementally by using "+ "++ and --. You can see all of your counters using "+ "\"inspect\", erase them with \"clear\", and view single counters with "+ "\"count\".") return true } -func (p *CounterPlugin) checkMatch(message msg.Message) bool { +func (p *CounterPlugin) checkMatch(c bot.Connector, message msg.Message) bool { nick := message.User.Name channel := message.Channel @@ -538,7 +538,7 @@ func (p *CounterPlugin) checkMatch(message msg.Message) bool { } log.Debug().Msgf("About to update item: %#v", item) item.UpdateDelta(1) - p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s... %s has %d %s", + p.Bot.Send(c, bot.Message, channel, fmt.Sprintf("%s... %s has %d %s", strings.Join(everyDayImShuffling([]string{"bleep", "bloop", "blop"}), "-"), nick, item.Count, itemName)) return true } diff --git a/plugins/counter/counter_test.go b/plugins/counter/counter_test.go index 417c44c..99f9212 100644 --- a/plugins/counter/counter_test.go +++ b/plugins/counter/counter_test.go @@ -4,6 +4,7 @@ package counter import ( "fmt" + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -22,12 +23,12 @@ func setup(t *testing.T) (*bot.MockBot, *CounterPlugin) { return mb, c } -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, @@ -250,6 +251,6 @@ func TestInspectMe(t *testing.T) { func TestHelp(t *testing.T) { mb, c := setup(t) assert.NotNil(t, c) - c.help(bot.Help, msg.Message{Channel: "channel"}, []string{}) + c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{}) assert.Len(t, mb.Messages, 1) } diff --git a/plugins/db/db.go b/plugins/db/db.go deleted file mode 100644 index a3799b9..0000000 --- a/plugins/db/db.go +++ /dev/null @@ -1,46 +0,0 @@ -package db - -import ( - "fmt" - "net/http" - "os" - "time" - - "github.com/rs/zerolog/log" - - "github.com/velour/catbase/bot" - "github.com/velour/catbase/bot/msg" - "github.com/velour/catbase/config" -) - -type DBPlugin struct { - bot bot.Bot - config *config.Config -} - -func New(b bot.Bot) *DBPlugin { - p := &DBPlugin{b, b.Config()} - p.registerWeb() - return p -} - -func (p *DBPlugin) Message(message msg.Message) bool { return false } -func (p *DBPlugin) Event(kind string, message msg.Message) bool { return false } -func (p *DBPlugin) ReplyMessage(msg.Message, string) bool { return false } -func (p *DBPlugin) BotMessage(message msg.Message) bool { return false } -func (p *DBPlugin) Help(channel string, parts []string) {} - -func (p *DBPlugin) registerWeb() { - http.HandleFunc("/db/catbase.db", p.serveQuery) -} - -func (p *DBPlugin) serveQuery(w http.ResponseWriter, r *http.Request) { - f, err := os.Open(p.bot.Config().DBFile) - defer f.Close() - if err != nil { - log.Error().Err(err).Msg("Error opening DB for web service") - fmt.Fprintf(w, "Error opening DB") - return - } - http.ServeContent(w, r, "catbase.db", time.Now(), f) -} diff --git a/plugins/dice/dice.go b/plugins/dice/dice.go index dafc715..b171820 100644 --- a/plugins/dice/dice.go +++ b/plugins/dice/dice.go @@ -35,7 +35,7 @@ func rollDie(sides int) int { // 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 *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *DicePlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if !message.Command { return false } @@ -49,7 +49,7 @@ func (p *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interfa } if sides < 2 || nDice < 1 || nDice > 20 { - p.Bot.Send(bot.Message, channel, "You're a dick.") + p.Bot.Send(c, bot.Message, channel, "You're a dick.") return true } @@ -64,13 +64,13 @@ func (p *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interfa } } - p.Bot.Send(bot.Message, channel, rolls) + p.Bot.Send(c, bot.Message, channel, rolls) return true } // Help responds to help requests. Every plugin must implement a help function. -func (p *DicePlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "Roll dice using notation XdY. Try \"3d20\".") +func (p *DicePlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.Bot.Send(c, bot.Message, message.Channel, "Roll dice using notation XdY. Try \"3d20\".") return true } diff --git a/plugins/dice/dice_test.go b/plugins/dice/dice_test.go index b7f2961..96eeb29 100644 --- a/plugins/dice/dice_test.go +++ b/plugins/dice/dice_test.go @@ -3,6 +3,7 @@ package dice import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, @@ -86,6 +87,6 @@ func TestHelp(t *testing.T) { mb := bot.NewMockBot() c := New(mb) assert.NotNil(t, c) - c.help(bot.Help, msg.Message{Channel: "channel"}, []string{}) + c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{}) assert.Len(t, mb.Messages, 1) } diff --git a/plugins/emojifyme/emojifyme.go b/plugins/emojifyme/emojifyme.go index 4a24d85..13ab96f 100644 --- a/plugins/emojifyme/emojifyme.go +++ b/plugins/emojifyme/emojifyme.go @@ -58,7 +58,7 @@ func New(b bot.Bot) *EmojifyMePlugin { return ep } -func (p *EmojifyMePlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *EmojifyMePlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if !p.GotBotEmoji { p.GotBotEmoji = true emojiMap := p.Bot.GetEmojiList() @@ -93,7 +93,7 @@ func (p *EmojifyMePlugin) message(kind bot.Kind, message msg.Message, args ...in if emojied > 0 && rand.Float64() <= p.Bot.Config().GetFloat64("Emojify.Chance", 0.02)*emojied { for _, e := range emojys { - p.Bot.Send(bot.Reaction, message.Channel, e, message) + p.Bot.Send(c, bot.Reaction, message.Channel, e, message) } return false } diff --git a/plugins/fact/fact_test.go b/plugins/fact/fact_test.go index c0fa9a9..c774146 100644 --- a/plugins/fact/fact_test.go +++ b/plugins/fact/fact_test.go @@ -1,6 +1,7 @@ package fact import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -10,6 +11,8 @@ import ( "github.com/velour/catbase/bot/user" ) +var c = &cli.CliPlugin{} + func makeMessage(nick, payload string) msg.Message { isCmd := strings.HasPrefix(payload, "!") if isCmd { @@ -37,7 +40,7 @@ func TestReact(t *testing.T) { p, mb := makePlugin(t) for _, m := range msgs { - p.message(bot.Message, m) + p.message(c, bot.Message, m) } assert.Len(t, mb.Reactions, 1) assert.Contains(t, mb.Reactions[0], "jesus") @@ -50,7 +53,7 @@ func TestReactCantLearnSpaces(t *testing.T) { p, mb := makePlugin(t) for _, m := range msgs { - p.message(bot.Message, m) + p.message(c, bot.Message, m) } assert.Len(t, mb.Messages, 1) assert.Contains(t, mb.Messages[0], "not a valid") diff --git a/plugins/fact/factoid.go b/plugins/fact/factoid.go index f7b25a5..eec9156 100644 --- a/plugins/fact/factoid.go +++ b/plugins/fact/factoid.go @@ -277,6 +277,8 @@ func New(botInst bot.Bot) *FactoidPlugin { db: botInst.DB(), } + c := botInst.DefaultConnector() + if _, err := p.db.Exec(`create table if not exists factoid ( id integer primary key, fact string, @@ -299,13 +301,13 @@ func New(botInst bot.Bot) *FactoidPlugin { } for _, channel := range botInst.Config().GetArray("channels", []string{}) { - go p.factTimer(channel) + go p.factTimer(c, channel) go func(ch string) { // Some random time to start up time.Sleep(time.Duration(15) * time.Second) if ok, fact := p.findTrigger(p.Bot.Config().Get("Factoid.StartupFact", "speed test")); ok { - p.sayFact(msg.Message{ + p.sayFact(c, msg.Message{ Channel: ch, Body: "speed test", // BUG: This is defined in the config too Command: true, @@ -399,7 +401,7 @@ func (p *FactoidPlugin) findTrigger(fact string) (bool, *Factoid) { // sayFact spits out a fact to the channel and updates the fact in the database // with new time and count information -func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) { +func (p *FactoidPlugin) sayFact(c bot.Connector, message msg.Message, fact Factoid) { msg := p.Bot.Filter(message, fact.Tidbit) full := p.Bot.Filter(message, fmt.Sprintf("%s %s %s", fact.Fact, fact.Verb, fact.Tidbit, @@ -411,13 +413,13 @@ func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) { } if fact.Verb == "action" { - p.Bot.Send(bot.Action, message.Channel, msg) + p.Bot.Send(c, bot.Action, message.Channel, msg) } else if fact.Verb == "react" { - p.Bot.Send(bot.Reaction, message.Channel, msg, message) + p.Bot.Send(c, bot.Reaction, message.Channel, msg, message) } else if fact.Verb == "reply" { - p.Bot.Send(bot.Message, message.Channel, msg) + p.Bot.Send(c, bot.Message, message.Channel, msg) } else { - p.Bot.Send(bot.Message, message.Channel, full) + p.Bot.Send(c, bot.Message, message.Channel, full) } } @@ -436,17 +438,17 @@ func (p *FactoidPlugin) sayFact(message msg.Message, fact Factoid) { // trigger checks the message for its fitness to be a factoid and then hauls // the message off to sayFact for processing if it is in fact a trigger -func (p *FactoidPlugin) trigger(message msg.Message) bool { +func (p *FactoidPlugin) trigger(c bot.Connector, message msg.Message) bool { minLen := p.Bot.Config().GetInt("Factoid.MinLen", 4) if len(message.Body) > minLen || message.Command || message.Body == "..." { if ok, fact := p.findTrigger(message.Body); ok { - p.sayFact(message, *fact) + p.sayFact(c, message, *fact) return true } r := strings.NewReplacer("'", "", "\"", "", ",", "", ".", "", ":", "", "?", "", "!", "") if ok, fact := p.findTrigger(r.Replace(message.Body)); ok { - p.sayFact(message, *fact) + p.sayFact(c, message, *fact) return true } } @@ -455,7 +457,7 @@ func (p *FactoidPlugin) trigger(message msg.Message) bool { } // tellThemWhatThatWas is a hilarious name for a function. -func (p *FactoidPlugin) tellThemWhatThatWas(message msg.Message) bool { +func (p *FactoidPlugin) tellThemWhatThatWas(c bot.Connector, message msg.Message) bool { fact := p.LastFact var msg string if fact == nil { @@ -464,11 +466,11 @@ func (p *FactoidPlugin) tellThemWhatThatWas(message msg.Message) bool { msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'", fact.ID.Int64, fact.Fact, fact.Verb, fact.Tidbit) } - p.Bot.Send(bot.Message, message.Channel, msg) + p.Bot.Send(c, bot.Message, message.Channel, msg) return true } -func (p *FactoidPlugin) learnAction(message msg.Message, action string) bool { +func (p *FactoidPlugin) learnAction(c bot.Connector, message msg.Message, action string) bool { body := message.Body parts := strings.SplitN(body, action, 2) @@ -482,21 +484,21 @@ func (p *FactoidPlugin) learnAction(message msg.Message, action string) bool { action = strings.TrimSpace(action) if len(trigger) == 0 || len(fact) == 0 || len(action) == 0 { - p.Bot.Send(bot.Message, message.Channel, "I don't want to learn that.") + p.Bot.Send(c, bot.Message, message.Channel, "I don't want to learn that.") return true } if len(strings.Split(fact, "$and")) > 4 { - p.Bot.Send(bot.Message, message.Channel, "You can't use more than 4 $and operators.") + p.Bot.Send(c, bot.Message, message.Channel, "You can't use more than 4 $and operators.") return true } strippedaction := strings.Replace(strings.Replace(action, "<", "", 1), ">", "", 1) if err := p.learnFact(message, trigger, strippedaction, fact); err != nil { - p.Bot.Send(bot.Message, message.Channel, err.Error()) + p.Bot.Send(c, bot.Message, message.Channel, err.Error()) } else { - p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name)) + p.Bot.Send(c, bot.Message, message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name)) } return true @@ -514,9 +516,9 @@ func changeOperator(body string) string { // If the user requesting forget is either the owner of the last learned fact or // an admin, it may be deleted -func (p *FactoidPlugin) forgetLastFact(message msg.Message) bool { +func (p *FactoidPlugin) forgetLastFact(c bot.Connector, message msg.Message) bool { if p.LastFact == nil { - p.Bot.Send(bot.Message, message.Channel, "I refuse.") + p.Bot.Send(c, bot.Message, message.Channel, "I refuse.") return true } @@ -529,14 +531,14 @@ func (p *FactoidPlugin) forgetLastFact(message msg.Message) bool { } fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.ID.Int64, p.LastFact.Fact, p.LastFact.Verb, p.LastFact.Tidbit) - p.Bot.Send(bot.Action, message.Channel, "hits himself over the head with a skillet") + p.Bot.Send(c, bot.Action, message.Channel, "hits himself over the head with a skillet") p.LastFact = nil return true } // Allow users to change facts with a simple regexp -func (p *FactoidPlugin) changeFact(message msg.Message) bool { +func (p *FactoidPlugin) changeFact(c bot.Connector, message msg.Message) bool { oper := changeOperator(message.Body) parts := strings.SplitN(message.Body, oper, 2) userexp := strings.TrimSpace(parts[1]) @@ -553,7 +555,7 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool { if len(parts) == 4 { // replacement if parts[0] != "s" { - p.Bot.Send(bot.Message, message.Channel, "Nah.") + p.Bot.Send(c, bot.Message, message.Channel, "Nah.") } find := parts[1] replace := parts[2] @@ -571,10 +573,10 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool { } // make the changes msg := fmt.Sprintf("Changing %d facts.", len(result)) - p.Bot.Send(bot.Message, message.Channel, msg) + p.Bot.Send(c, bot.Message, message.Channel, msg) reg, err := regexp.Compile(find) if err != nil { - p.Bot.Send(bot.Message, message.Channel, "I don't really want to.") + p.Bot.Send(c, bot.Message, message.Channel, "I don't really want to.") return false } for _, fact := range result { @@ -594,19 +596,19 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool { Err(err). Str("trigger", trigger). Msg("Error getting facts") - p.Bot.Send(bot.Message, message.Channel, "bzzzt") + p.Bot.Send(c, bot.Message, message.Channel, "bzzzt") return true } count := len(result) if count == 0 { - p.Bot.Send(bot.Message, message.Channel, "I didn't find any facts like that.") + p.Bot.Send(c, bot.Message, message.Channel, "I didn't find any facts like that.") return true } if parts[2] == "g" && len(result) > 4 { // summarize result = result[:4] } else { - p.sayFact(message, *result[0]) + p.sayFact(c, message, *result[0]) return true } msg := fmt.Sprintf("%s ", trigger) @@ -619,9 +621,9 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool { if count > 4 { msg = fmt.Sprintf("%s | ...and %d others", msg, count) } - p.Bot.Send(bot.Message, message.Channel, msg) + p.Bot.Send(c, bot.Message, message.Channel, msg) } else { - p.Bot.Send(bot.Message, message.Channel, "I don't know what you mean.") + p.Bot.Send(c, bot.Message, message.Channel, "I don't know what you mean.") } return true } @@ -629,15 +631,15 @@ func (p *FactoidPlugin) changeFact(message msg.Message) bool { // 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(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *FactoidPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if strings.ToLower(message.Body) == "what was that?" { - return p.tellThemWhatThatWas(message) + return p.tellThemWhatThatWas(c, message) } // 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) + return p.trigger(c, message) } if strings.HasPrefix(strings.ToLower(message.Body), "alias") { @@ -647,53 +649,53 @@ func (p *FactoidPlugin) message(kind bot.Kind, message msg.Message, args ...inte m := strings.TrimPrefix(message.Body, "alias ") parts := strings.SplitN(m, "->", 2) if len(parts) != 2 { - p.Bot.Send(bot.Message, message.Channel, "If you want to alias something, use: `alias this -> that`") + p.Bot.Send(c, bot.Message, message.Channel, "If you want to alias something, use: `alias this -> that`") return true } a := aliasFromStrings(strings.TrimSpace(parts[1]), strings.TrimSpace(parts[0])) if err := a.save(p.db); err != nil { - p.Bot.Send(bot.Message, message.Channel, err.Error()) + p.Bot.Send(c, bot.Message, message.Channel, err.Error()) } else { - p.Bot.Send(bot.Action, message.Channel, "learns a new synonym") + p.Bot.Send(c, bot.Action, message.Channel, "learns a new synonym") } return true } if strings.ToLower(message.Body) == "factoid" { if fact := p.randomFact(); fact != nil { - p.sayFact(message, *fact) + p.sayFact(c, message, *fact) return true } log.Debug().Msg("Got a nil fact.") } if strings.ToLower(message.Body) == "forget that" { - return p.forgetLastFact(message) + return p.forgetLastFact(c, message) } if changeOperator(message.Body) != "" { - return p.changeFact(message) + return p.changeFact(c, message) } action := findAction(message.Body) if action != "" { - return p.learnAction(message, action) + return p.learnAction(c, message, action) } // look for any triggers in the db matching this message - if p.trigger(message) { + if p.trigger(c, message) { return true } // We didn't find anything, panic! - p.Bot.Send(bot.Message, message.Channel, p.NotFound[rand.Intn(len(p.NotFound))]) + p.Bot.Send(c, bot.Message, message.Channel, p.NotFound[rand.Intn(len(p.NotFound))]) return true } // Help responds to help requests. Every plugin must implement a help function. -func (p *FactoidPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.") - p.Bot.Send(bot.Message, message.Channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.") +func (p *FactoidPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.Bot.Send(c, bot.Message, message.Channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.") + p.Bot.Send(c, bot.Message, message.Channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.") return true } @@ -708,7 +710,7 @@ func (p *FactoidPlugin) randomFact() *Factoid { } // factTimer spits out a fact at a given interval and with given probability -func (p *FactoidPlugin) factTimer(channel string) { +func (p *FactoidPlugin) factTimer(c bot.Connector, channel string) { quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime", 30) if quoteTime == 0 { quoteTime = 30 @@ -749,7 +751,7 @@ func (p *FactoidPlugin) factTimer(channel string) { User: &users[rand.Intn(len(users))], Channel: channel, } - p.sayFact(message, *fact) + p.sayFact(c, message, *fact) myLastMsg = time.Now() } } diff --git a/plugins/fact/webTemplates.go b/plugins/fact/webTemplates.go index d3f7ee6..0c0c7b7 100644 --- a/plugins/fact/webTemplates.go +++ b/plugins/fact/webTemplates.go @@ -7,7 +7,7 @@ package fact // 2016-01-15 Later note, why are these in plugins and the server is in bot? -var factoidIndex string = ` +var factoidIndex = ` diff --git a/plugins/first/first.go b/plugins/first/first.go index c0a35b0..7e26b6c 100644 --- a/plugins/first/first.go +++ b/plugins/first/first.go @@ -132,14 +132,14 @@ func isToday(t time.Time) bool { // 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 *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *FirstPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { // This bot does not reply to anything if p.First == nil && p.allowed(message) { log.Debug(). Str("body", message.Body). Msg("No previous first. Recording new first") - p.recordFirst(message) + p.recordFirst(c, message) return false } else if p.First != nil { if isToday(p.First.time) && p.allowed(message) { @@ -148,7 +148,7 @@ func (p *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interf Time("t0", p.First.time). Time("t1", time.Now()). Msg("Recording first") - p.recordFirst(message) + p.recordFirst(c, message) return false } } @@ -157,7 +157,7 @@ func (p *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interf "?", "", "!", "") msg := strings.ToLower(message.Body) if r.Replace(msg) == "whos on first" { - p.announceFirst(message) + p.announceFirst(c, message) return true } @@ -199,7 +199,7 @@ func (p *FirstPlugin) allowed(message msg.Message) bool { return true } -func (p *FirstPlugin) recordFirst(message msg.Message) { +func (p *FirstPlugin) recordFirst(c bot.Connector, message msg.Message) { log.Info(). Str("user", message.User.Name). Str("body", message.Body). @@ -216,13 +216,13 @@ func (p *FirstPlugin) recordFirst(message msg.Message) { log.Error().Err(err).Msg("Error saving first entry") return } - p.announceFirst(message) + p.announceFirst(c, message) } -func (p *FirstPlugin) announceFirst(message msg.Message) { - c := message.Channel +func (p *FirstPlugin) announceFirst(c bot.Connector, message msg.Message) { + ch := message.Channel if p.First != nil { - p.Bot.Send(bot.Message, c, fmt.Sprintf("%s had first at %s with the message: \"%s\"", + p.Bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"", p.First.nick, p.First.time.Format("15:04"), p.First.body)) } } @@ -235,7 +235,7 @@ func (p *FirstPlugin) LoadData() { } // Help responds to help requests. Every plugin must implement a help function. -func (p *FirstPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.") +func (p *FirstPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.Bot.Send(c, bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.") return true } diff --git a/plugins/inventory/inventory.go b/plugins/inventory/inventory.go index b1fb2bf..2eb4a2f 100644 --- a/plugins/inventory/inventory.go +++ b/plugins/inventory/inventory.go @@ -78,7 +78,7 @@ func (p *InventoryPlugin) itemFilter(input string) string { return input } -func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *InventoryPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { m := message.Body log.Debug().Msgf("inventory trying to read %+v", message) if message.Command { @@ -89,7 +89,7 @@ func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...in log.Debug().Msgf("I think I have more than 0 items: %+v, len(items)=%d", items, len(items)) say = fmt.Sprintf("I'm currently holding %s", strings.Join(items, ", ")) } - p.bot.Send(bot.Message, message.Channel, say) + p.bot.Send(c, bot.Message, message.Channel, say) return true } @@ -97,11 +97,11 @@ func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...in // Bucket[:,] have a (.+) if matches := p.r1.FindStringSubmatch(m); len(matches) > 0 { log.Debug().Msgf("Found item to add: %s", matches[1]) - return p.addItem(message, matches[1]) + return p.addItem(c, message, matches[1]) } if matches := p.r2.FindStringSubmatch(m); len(matches) > 0 { log.Debug().Msgf("Found item to add: %s", matches[1]) - return p.addItem(message, matches[1]) + return p.addItem(c, message, matches[1]) } } if message.Action { @@ -112,15 +112,15 @@ func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...in if matches := p.r3.FindStringSubmatch(m); len(matches) > 0 { log.Debug().Msgf("Found item to add: %s", matches[1]) - return p.addItem(message, matches[1]) + return p.addItem(c, message, matches[1]) } if matches := p.r4.FindStringSubmatch(m); len(matches) > 0 { log.Debug().Msgf("Found item to add: %s", matches[1]) - return p.addItem(message, matches[1]) + return p.addItem(c, message, matches[1]) } if matches := p.r5.FindStringSubmatch(m); len(matches) > 0 { log.Debug().Msgf("Found item to add: %s", matches[1]) - return p.addItem(message, matches[1]) + return p.addItem(c, message, matches[1]) } } return false @@ -198,9 +198,9 @@ func (p *InventoryPlugin) remove(i string) { } } -func (p *InventoryPlugin) addItem(m msg.Message, i string) bool { +func (p *InventoryPlugin) addItem(c bot.Connector, m msg.Message, i string) bool { if p.exists(i) { - p.bot.Send(bot.Message, m.Channel, fmt.Sprintf("I already have %s.", i)) + p.bot.Send(c, bot.Message, m.Channel, fmt.Sprintf("I already have %s.", i)) return true } var removed string @@ -213,9 +213,9 @@ func (p *InventoryPlugin) addItem(m msg.Message, i string) bool { log.Error().Err(err).Msg("Error inserting new inventory item") } if removed != "" { - p.bot.Send(bot.Action, m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name)) + p.bot.Send(c, bot.Action, m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name)) } else { - p.bot.Send(bot.Action, m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name)) + p.bot.Send(c, bot.Action, m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name)) } return true } diff --git a/plugins/leftpad/leftpad.go b/plugins/leftpad/leftpad.go index 23847f2..0c97399 100644 --- a/plugins/leftpad/leftpad.go +++ b/plugins/leftpad/leftpad.go @@ -33,7 +33,7 @@ type leftpadResp struct { Str string } -func (p *LeftpadPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *LeftpadPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if !message.Command { return false } @@ -43,20 +43,20 @@ func (p *LeftpadPlugin) message(kind bot.Kind, message msg.Message, args ...inte padchar := parts[1] length, err := strconv.Atoi(parts[2]) if err != nil { - p.bot.Send(bot.Message, message.Channel, "Invalid padding number") + p.bot.Send(c, bot.Message, message.Channel, "Invalid padding number") return true } maxLen, who := p.config.GetInt("LeftPad.MaxLen", 50), p.config.Get("LeftPad.Who", "Putin") if length > maxLen && maxLen > 0 { msg := fmt.Sprintf("%s would kill me if I did that.", who) - p.bot.Send(bot.Message, message.Channel, msg) + p.bot.Send(c, bot.Message, message.Channel, msg) return true } text := strings.Join(parts[3:], " ") res := leftpad.LeftPad(text, length, padchar) - p.bot.Send(bot.Message, message.Channel, res) + p.bot.Send(c, bot.Message, message.Channel, res) return true } diff --git a/plugins/leftpad/leftpad_test.go b/plugins/leftpad/leftpad_test.go index 32b9cdc..fcfc10b 100644 --- a/plugins/leftpad/leftpad_test.go +++ b/plugins/leftpad/leftpad_test.go @@ -3,6 +3,7 @@ package leftpad import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -13,12 +14,12 @@ import ( "github.com/velour/catbase/plugins/counter" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/nerdepedia/nerdepedia.go b/plugins/nerdepedia/nerdepedia.go index 6c0ba3c..d463425 100644 --- a/plugins/nerdepedia/nerdepedia.go +++ b/plugins/nerdepedia/nerdepedia.go @@ -40,7 +40,7 @@ func New(b bot.Bot) *NerdepediaPlugin { // 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 *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *NerdepediaPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { lowerCase := strings.ToLower(message.Body) query := "" if lowerCase == "may the force be with you" || lowerCase == "help me obi-wan" { @@ -81,7 +81,7 @@ func (p *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...i } if description != "" && link != "" { - p.bot.Send(bot.Message, message.Channel, fmt.Sprintf("%s (%s)", description, link)) + p.bot.Send(c, bot.Message, message.Channel, fmt.Sprintf("%s (%s)", description, link)) return true } } @@ -90,7 +90,7 @@ func (p *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...i } // Help responds to help requests. Every plugin must implement a help function. -func (p *NerdepediaPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.bot.Send(bot.Message, message.Channel, "nerd stuff") +func (p *NerdepediaPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "nerd stuff") return true } diff --git a/plugins/nerdepedia/nerdepeida_test.go b/plugins/nerdepedia/nerdepeida_test.go index eb59807..a135a31 100644 --- a/plugins/nerdepedia/nerdepeida_test.go +++ b/plugins/nerdepedia/nerdepeida_test.go @@ -3,6 +3,7 @@ package nerdepedia import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/picker/picker.go b/plugins/picker/picker.go index b7290d4..51d6b3f 100644 --- a/plugins/picker/picker.go +++ b/plugins/picker/picker.go @@ -16,13 +16,13 @@ import ( ) type PickerPlugin struct { - Bot bot.Bot + bot bot.Bot } // NewPickerPlugin creates a new PickerPlugin with the Plugin interface func New(b bot.Bot) *PickerPlugin { pp := &PickerPlugin{ - Bot: b, + bot: b, } b.Register(pp, bot.Message, pp.message) b.Register(pp, bot.Help, pp.help) @@ -32,21 +32,21 @@ func New(b bot.Bot) *PickerPlugin { // 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 *PickerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *PickerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if !strings.HasPrefix(message.Body, "pick") { return false } n, items, err := p.parse(message.Body) if err != nil { - p.Bot.Send(bot.Message, message.Channel, err.Error()) + p.bot.Send(c, bot.Message, message.Channel, err.Error()) return true } if n == 1 { item := items[rand.Intn(len(items))] out := fmt.Sprintf("I've chosen %q for you.", strings.TrimSpace(item)) - p.Bot.Send(bot.Message, message.Channel, out) + p.bot.Send(c, bot.Message, message.Channel, out) return true } @@ -62,7 +62,7 @@ func (p *PickerPlugin) message(kind bot.Kind, message msg.Message, args ...inter fmt.Fprintf(&b, ", %q", item) } b.WriteString(" }") - p.Bot.Send(bot.Message, message.Channel, b.String()) + p.bot.Send(c, bot.Message, message.Channel, b.String()) return true } @@ -111,7 +111,7 @@ func (p *PickerPlugin) parse(body string) (int, []string, error) { } // Help responds to help requests. Every plugin must implement a help function. -func (p *PickerPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "Choose from a list of options. Try \"pick {a,b,c}\".") +func (p *PickerPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "Choose from a list of options. Try \"pick {a,b,c}\".") return true } diff --git a/plugins/picker/picker_test.go b/plugins/picker/picker_test.go index b01684a..c1901c6 100644 --- a/plugins/picker/picker_test.go +++ b/plugins/picker/picker_test.go @@ -3,6 +3,7 @@ package picker import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/reaction/reaction.go b/plugins/reaction/reaction.go index 3dcd078..a4a5f55 100644 --- a/plugins/reaction/reaction.go +++ b/plugins/reaction/reaction.go @@ -11,38 +11,38 @@ import ( ) type ReactionPlugin struct { - Bot bot.Bot - Config *config.Config + bot bot.Bot + config *config.Config } func New(b bot.Bot) *ReactionPlugin { rp := &ReactionPlugin{ - Bot: b, - Config: b.Config(), + bot: b, + config: b.Config(), } b.Register(rp, bot.Message, rp.message) return rp } -func (p *ReactionPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *ReactionPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { harrass := false - for _, nick := range p.Config.GetArray("Reaction.HarrassList", []string{}) { + for _, nick := range p.config.GetArray("Reaction.HarrassList", []string{}) { if message.User.Name == nick { harrass = true break } } - chance := p.Config.GetFloat64("Reaction.GeneralChance", 0.01) + chance := p.config.GetFloat64("Reaction.GeneralChance", 0.01) negativeWeight := 1 if harrass { - chance = p.Config.GetFloat64("Reaction.HarrassChance", 0.05) - negativeWeight = p.Config.GetInt("Reaction.NegativeHarrassmentMultiplier", 2) + chance = p.config.GetFloat64("Reaction.HarrassChance", 0.05) + negativeWeight = p.config.GetInt("Reaction.NegativeHarrassmentMultiplier", 2) } if rand.Float64() < chance { - numPositiveReactions := len(p.Config.GetArray("Reaction.PositiveReactions", []string{})) - numNegativeReactions := len(p.Config.GetArray("Reaction.NegativeReactions", []string{})) + numPositiveReactions := len(p.config.GetArray("Reaction.PositiveReactions", []string{})) + numNegativeReactions := len(p.config.GetArray("Reaction.NegativeReactions", []string{})) maxIndex := numPositiveReactions + numNegativeReactions*negativeWeight @@ -51,14 +51,14 @@ func (p *ReactionPlugin) message(kind bot.Kind, message msg.Message, args ...int reaction := "" if index < numPositiveReactions { - reaction = p.Config.GetArray("Reaction.PositiveReactions", []string{})[index] + reaction = p.config.GetArray("Reaction.PositiveReactions", []string{})[index] } else { index -= numPositiveReactions index %= numNegativeReactions - reaction = p.Config.GetArray("Reaction.NegativeReactions", []string{})[index] + reaction = p.config.GetArray("Reaction.NegativeReactions", []string{})[index] } - p.Bot.Send(bot.Reaction, message.Channel, reaction, message) + p.bot.Send(c, bot.Reaction, message.Channel, reaction, message) } return false diff --git a/plugins/remember/remember.go b/plugins/remember/remember.go index 67bad5d..c56a105 100644 --- a/plugins/remember/remember.go +++ b/plugins/remember/remember.go @@ -32,10 +32,10 @@ func New(b bot.Bot) *RememberPlugin { return p } -func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *RememberPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if strings.ToLower(message.Body) == "quote" && message.Command { q := p.randQuote() - p.bot.Send(bot.Message, message.Channel, q) + p.bot.Send(c, bot.Message, message.Channel, q) // is it evil not to remember that the user said quote? return true @@ -82,7 +82,7 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int } if err := fact.Save(p.db); err != nil { log.Error().Err(err) - p.bot.Send(bot.Message, message.Channel, "Tell somebody I'm broke.") + p.bot.Send(c, bot.Message, message.Channel, "Tell somebody I'm broke.") } log.Info(). @@ -92,13 +92,13 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int // sorry, not creative with names so we're reusing msg msg = fmt.Sprintf("Okay, %s, remembering '%s'.", message.User.Name, msg) - p.bot.Send(bot.Message, message.Channel, msg) + p.bot.Send(c, bot.Message, message.Channel, msg) p.recordMsg(message) return true } } - p.bot.Send(bot.Message, message.Channel, "Sorry, I don't know that phrase.") + p.bot.Send(c, bot.Message, message.Channel, "Sorry, I don't know that phrase.") p.recordMsg(message) return true } @@ -107,13 +107,13 @@ func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...int return false } -func (p *RememberPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *RememberPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { msg := "remember will let you quote your idiot friends. Just type " + "!remember to remember what they said. Snippet can " + "be any part of their message. Later on, you can ask for a random " + "!quote." - p.bot.Send(bot.Message, message.Channel, msg) + p.bot.Send(c, bot.Message, message.Channel, msg) return true } diff --git a/plugins/remember/remember_test.go b/plugins/remember/remember_test.go index 8a1512a..91fa566 100644 --- a/plugins/remember/remember_test.go +++ b/plugins/remember/remember_test.go @@ -1,6 +1,7 @@ package remember import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -43,7 +44,7 @@ func TestCornerCaseBug(t *testing.T) { p, _, mb := makePlugin(t) for _, m := range msgs { - p.message(bot.Message, m) + p.message(&cli.CliPlugin{}, bot.Message, m) } assert.Len(t, mb.Messages, 1) assert.Contains(t, mb.Messages[0], "horse dick") diff --git a/plugins/reminder/reminder.go b/plugins/reminder/reminder.go index bdc4568..d4003e9 100644 --- a/plugins/reminder/reminder.go +++ b/plugins/reminder/reminder.go @@ -27,7 +27,7 @@ const ( ) type ReminderPlugin struct { - Bot bot.Bot + bot bot.Bot db *sqlx.DB mutex *sync.Mutex timer *time.Timer @@ -65,7 +65,7 @@ func New(b bot.Bot) *ReminderPlugin { w.Add(common.All...) plugin := &ReminderPlugin{ - Bot: b, + bot: b, db: b.DB(), mutex: &sync.Mutex{}, timer: timer, @@ -75,7 +75,7 @@ func New(b bot.Bot) *ReminderPlugin { plugin.queueUpNextReminder() - go reminderer(plugin) + go reminderer(b.DefaultConnector(), plugin) b.Register(plugin, bot.Message, plugin.message) b.Register(plugin, bot.Help, plugin.help) @@ -83,7 +83,7 @@ func New(b bot.Bot) *ReminderPlugin { return plugin } -func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *ReminderPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { channel := message.Channel from := message.User.Name @@ -109,7 +109,7 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int dur, err = time.ParseDuration(parts[3]) if err != nil { - p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.") + p.bot.Send(c, bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.") return true } @@ -137,7 +137,7 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int dur2, err = time.ParseDuration(parts[5]) if err != nil { log.Error().Err(err) - p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.") + p.bot.Send(c, bot.Message, channel, "Easy cowboy, not sure I can parse that duration. Try something like '1.5h' or '2h45m'.") return true } @@ -148,7 +148,7 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int max := p.config.GetInt("Reminder.MaxBatchAdd", 10) for i := 0; when.Before(endTime); i++ { if i >= max { - p.Bot.Send(bot.Message, channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.") + p.bot.Send(c, bot.Message, channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.") doConfirm = false break } @@ -165,14 +165,14 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int when = when.Add(dur) } } else { - p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I comprehend what you're asking.") + p.bot.Send(c, bot.Message, channel, "Easy cowboy, not sure I comprehend what you're asking.") return true } if doConfirm && from == who { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("Okay. I'll remind you.")) + p.bot.Send(c, bot.Message, channel, fmt.Sprintf("Okay. I'll remind you.")) } else if doConfirm { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("Sure %s, I'll remind %s.", from, who)) + p.bot.Send(c, bot.Message, channel, fmt.Sprintf("Sure %s, I'll remind %s.", from, who)) } p.queueUpNextReminder() @@ -192,22 +192,22 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int } } if err != nil { - p.Bot.Send(bot.Message, channel, "listing failed.") + p.bot.Send(c, bot.Message, channel, "listing failed.") } else { - p.Bot.Send(bot.Message, channel, response) + p.bot.Send(c, bot.Message, channel, response) } return true } else if len(parts) == 3 && strings.ToLower(parts[0]) == "cancel" && strings.ToLower(parts[1]) == "reminder" { id, err := strconv.ParseInt(parts[2], 10, 64) if err != nil { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("couldn't parse id: %s", parts[2])) + p.bot.Send(c, bot.Message, channel, fmt.Sprintf("couldn't parse id: %s", parts[2])) } else { err := p.deleteReminder(id) if err == nil { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("successfully canceled reminder: %s", parts[2])) + p.bot.Send(c, bot.Message, channel, fmt.Sprintf("successfully canceled reminder: %s", parts[2])) } else { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("failed to find and cancel reminder: %s", parts[2])) + p.bot.Send(c, bot.Message, channel, fmt.Sprintf("failed to find and cancel reminder: %s", parts[2])) } } return true @@ -216,8 +216,8 @@ func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...int return false } -func (p *ReminderPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "Pester someone with a reminder. Try \"remind in message\".\n\nUnsure about duration syntax? Check https://golang.org/pkg/time/#ParseDuration") +func (p *ReminderPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "Pester someone with a reminder. Try \"remind in message\".\n\nUnsure about duration syntax? Check https://golang.org/pkg/time/#ParseDuration") return true } @@ -351,7 +351,7 @@ func (p *ReminderPlugin) queueUpNextReminder() { } } -func reminderer(p *ReminderPlugin) { +func reminderer(c bot.Connector, p *ReminderPlugin) { for { <-p.timer.C @@ -366,7 +366,7 @@ func reminderer(p *ReminderPlugin) { message = fmt.Sprintf("Hey %s, %s wanted you to be reminded: %s", reminder.who, reminder.from, reminder.what) } - p.Bot.Send(bot.Message, reminder.channel, message) + p.bot.Send(c, bot.Message, reminder.channel, message) if err := p.deleteReminder(reminder.id); err != nil { log.Error(). diff --git a/plugins/reminder/reminder_test.go b/plugins/reminder/reminder_test.go index 457397d..04a4622 100644 --- a/plugins/reminder/reminder_test.go +++ b/plugins/reminder/reminder_test.go @@ -4,6 +4,7 @@ package reminder import ( "fmt" + "github.com/velour/catbase/plugins/cli" "strings" "testing" "time" @@ -14,16 +15,16 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { return makeMessageBy(payload, "tester") } -func makeMessageBy(payload, by string) (bot.Kind, msg.Message) { +func makeMessageBy(payload, by string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: by}, Channel: "test", Body: payload, @@ -223,6 +224,6 @@ func TestLimitList(t *testing.T) { func TestHelp(t *testing.T) { c, mb := setup(t) assert.NotNil(t, c) - c.help(bot.Help, msg.Message{Channel: "channel"}, []string{}) + c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{}) assert.Len(t, mb.Messages, 1) } diff --git a/plugins/rpgORdie/rpgORdie.go b/plugins/rpgORdie/rpgORdie.go index 1035a06..527d808 100644 --- a/plugins/rpgORdie/rpgORdie.go +++ b/plugins/rpgORdie/rpgORdie.go @@ -20,7 +20,7 @@ const ( ) type RPGPlugin struct { - Bot bot.Bot + bot bot.Bot listenFor map[string]*board } @@ -99,7 +99,7 @@ func (b *board) checkAndMove(dx, dy int) int { func New(b bot.Bot) *RPGPlugin { rpg := &RPGPlugin{ - Bot: b, + bot: b, listenFor: map[string]*board{}, } b.Register(rpg, bot.Message, rpg.message) @@ -108,25 +108,25 @@ func New(b bot.Bot) *RPGPlugin { return rpg } -func (p *RPGPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *RPGPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if strings.ToLower(message.Body) == "start rpg" { b := NewRandomBoard() - ts, _ := p.Bot.Send(bot.Message, message.Channel, b.toMessageString()) + ts, _ := p.bot.Send(c, bot.Message, message.Channel, b.toMessageString()) p.listenFor[ts] = b - p.Bot.Send(bot.Reply, message.Channel, "Over here.", ts) + p.bot.Send(c, bot.Reply, message.Channel, "Over here.", ts) return true } return false } -func (p *RPGPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "Go find a walkthrough or something.") +func (p *RPGPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "Go find a walkthrough or something.") return true } -func (p *RPGPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *RPGPlugin) replyMessage(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { identifier := args[0].(string) - if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) { + if strings.ToLower(message.User.Name) != strings.ToLower(p.bot.Config().Get("Nick", "bot")) { if b, ok := p.listenFor[identifier]; ok { var res int @@ -145,12 +145,12 @@ func (p *RPGPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...int switch res { case OK: - p.Bot.Send(bot.Edit, message.Channel, b.toMessageString(), identifier) + p.bot.Send(c, bot.Edit, message.Channel, b.toMessageString(), identifier) case WIN: - p.Bot.Send(bot.Edit, message.Channel, b.toMessageString(), identifier) - p.Bot.Send(bot.Reply, message.Channel, "congratulations, you beat the easiest level imaginable.", identifier) + p.bot.Send(c, bot.Edit, message.Channel, b.toMessageString(), identifier) + p.bot.Send(c, bot.Reply, message.Channel, "congratulations, you beat the easiest level imaginable.", identifier) case INVALID: - p.Bot.Send(bot.Reply, message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier) + p.bot.Send(c, bot.Reply, message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier) } return true } diff --git a/plugins/rpgORdie/rpgORdie_test.go b/plugins/rpgORdie/rpgORdie_test.go index ddcd924..86f7a77 100644 --- a/plugins/rpgORdie/rpgORdie_test.go +++ b/plugins/rpgORdie/rpgORdie_test.go @@ -1,3 +1 @@ package rpgORdie - -import () diff --git a/plugins/rss/rss.go b/plugins/rss/rss.go index 811f37f..41cdcc1 100644 --- a/plugins/rss/rss.go +++ b/plugins/rss/rss.go @@ -12,7 +12,7 @@ import ( ) type RSSPlugin struct { - Bot bot.Bot + bot bot.Bot cache map[string]*cacheItem shelfLife time.Duration maxLines int @@ -51,7 +51,7 @@ func (c *cacheItem) getCurrentPage(maxLines int) string { func New(b bot.Bot) *RSSPlugin { rss := &RSSPlugin{ - Bot: b, + bot: b, cache: map[string]*cacheItem{}, shelfLife: time.Minute * time.Duration(b.Config().GetInt("rss.shelfLife", 20)), maxLines: b.Config().GetInt("rss.maxLines", 5), @@ -61,19 +61,19 @@ func New(b bot.Bot) *RSSPlugin { return rss } -func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *RSSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { tokens := strings.Fields(message.Body) numTokens := len(tokens) if numTokens == 2 && strings.ToLower(tokens[0]) == "rss" { if item, ok := p.cache[strings.ToLower(tokens[1])]; ok && time.Now().Before(item.expiration) { - p.Bot.Send(bot.Message, message.Channel, item.getCurrentPage(p.maxLines)) + p.bot.Send(c, bot.Message, message.Channel, item.getCurrentPage(p.maxLines)) return true } else { fp := gofeed.NewParser() feed, err := fp.ParseURL(tokens[1]) if err != nil { - p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("RSS error: %s", err.Error())) + p.bot.Send(c, bot.Message, message.Channel, fmt.Sprintf("RSS error: %s", err.Error())) return true } item := &cacheItem{ @@ -89,7 +89,7 @@ func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interfac p.cache[strings.ToLower(tokens[1])] = item - p.Bot.Send(bot.Message, message.Channel, item.getCurrentPage(p.maxLines)) + p.bot.Send(c, bot.Message, message.Channel, item.getCurrentPage(p.maxLines)) return true } } @@ -98,7 +98,7 @@ func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interfac } // Help responds to help requests. Every plugin must implement a help function. -func (p *RSSPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "try '!rss http://rss.cnn.com/rss/edition.rss'") +func (p *RSSPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "try '!rss http://rss.cnn.com/rss/edition.rss'") return true } diff --git a/plugins/rss/rss_test.go b/plugins/rss/rss_test.go index 900031a..110fdf2 100644 --- a/plugins/rss/rss_test.go +++ b/plugins/rss/rss_test.go @@ -2,6 +2,7 @@ package rss import ( "fmt" + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -11,12 +12,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/sisyphus/sisyphus.go b/plugins/sisyphus/sisyphus.go index 6238596..4bb607f 100644 --- a/plugins/sisyphus/sisyphus.go +++ b/plugins/sisyphus/sisyphus.go @@ -19,7 +19,7 @@ const ( ) type SisyphusPlugin struct { - Bot bot.Bot + bot bot.Bot listenFor map[string]*game } @@ -38,7 +38,7 @@ type game struct { nextAns int } -func NewRandomGame(b bot.Bot, channel, who string) *game { +func NewRandomGame(c bot.Connector, b bot.Bot, channel, who string) *game { size := rand.Intn(9) + 2 g := game{ channel: channel, @@ -48,32 +48,32 @@ func NewRandomGame(b bot.Bot, channel, who string) *game { size: size, current: size / 2, } - g.id, _ = b.Send(bot.Message, channel, g.toMessageString()) + g.id, _ = b.Send(c, bot.Message, channel, g.toMessageString()) - g.schedulePush() - g.scheduleDecrement() + g.schedulePush(c) + g.scheduleDecrement(c) return &g } -func (g *game) scheduleDecrement() { +func (g *game) scheduleDecrement(c bot.Connector) { if g.timers[0] != nil { g.timers[0].Stop() } minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement", 10) maxDec := g.bot.Config().GetInt("Sisyphus.MaxDecrement", 30) - g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute) + g.nextDec = time.Now().Add(time.Duration(minDec+rand.Intn(maxDec)) * time.Minute) go func() { t := time.NewTimer(g.nextDec.Sub(time.Now())) g.timers[0] = t select { case <-t.C: - g.handleDecrement() + g.handleDecrement(c) } }() } -func (g *game) schedulePush() { +func (g *game) schedulePush(c bot.Connector) { if g.timers[1] != nil { g.timers[1].Stop() } @@ -85,7 +85,7 @@ func (g *game) schedulePush() { g.timers[1] = t select { case <-t.C: - g.handleNotify() + g.handleNotify(c) } }() } @@ -97,21 +97,21 @@ func (g *game) endGame() { g.ended = true } -func (g *game) handleDecrement() { +func (g *game) handleDecrement(c bot.Connector) { g.current++ - g.bot.Send(bot.Edit, g.channel, g.toMessageString(), g.id) + g.bot.Send(c, bot.Edit, g.channel, g.toMessageString(), g.id) if g.current > g.size-2 { - g.bot.Send(bot.Reply, g.channel, "you lose", g.id) + g.bot.Send(c, bot.Reply, g.channel, "you lose", g.id) msg := fmt.Sprintf("%s just lost the game after %s", g.who, time.Now().Sub(g.start)) - g.bot.Send(bot.Message, g.channel, msg) + g.bot.Send(c, bot.Message, g.channel, msg) g.endGame() } else { - g.scheduleDecrement() + g.scheduleDecrement(c) } } -func (g *game) handleNotify() { - g.bot.Send(bot.Reply, g.channel, "You can push now.\n"+g.generateQuestion(), g.id) +func (g *game) handleNotify(c bot.Connector) { + g.bot.Send(c, bot.Reply, g.channel, "You can push now.\n"+g.generateQuestion(), g.id) } func (g *game) generateQuestion() string { @@ -164,7 +164,7 @@ func (g *game) toMessageString() string { func New(b bot.Bot) *SisyphusPlugin { sp := &SisyphusPlugin{ - Bot: b, + bot: b, listenFor: map[string]*game{}, } b.Register(sp, bot.Message, sp.message) @@ -173,24 +173,24 @@ func New(b bot.Bot) *SisyphusPlugin { return sp } -func (p *SisyphusPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *SisyphusPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if strings.ToLower(message.Body) == "start sisyphus" { - b := NewRandomGame(p.Bot, message.Channel, message.User.Name) + b := NewRandomGame(c, p.bot, message.Channel, message.User.Name) p.listenFor[b.id] = b - p.Bot.Send(bot.Reply, message.Channel, "Over here.", b.id) + p.bot.Send(c, bot.Reply, message.Channel, "Over here.", b.id) return true } return false } -func (p *SisyphusPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "https://en.wikipedia.org/wiki/Sisyphus") +func (p *SisyphusPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "https://en.wikipedia.org/wiki/Sisyphus") return true } -func (p *SisyphusPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *SisyphusPlugin) replyMessage(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { identifier := args[0].(string) - if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) { + if strings.ToLower(message.User.Name) != strings.ToLower(p.bot.Config().Get("Nick", "bot")) { if g, ok := p.listenFor[identifier]; ok { log.Debug().Msgf("got message on %s: %+v", identifier, message) @@ -206,18 +206,18 @@ func (p *SisyphusPlugin) replyMessage(kind bot.Kind, message msg.Message, args . if time.Now().After(g.nextPush) { if g.checkAnswer(message.Body) { - p.Bot.Send(bot.Edit, message.Channel, g.toMessageString(), identifier) - g.schedulePush() + p.bot.Send(c, bot.Edit, message.Channel, g.toMessageString(), identifier) + g.schedulePush(c) msg := fmt.Sprintf("Ok. You can push again in %s", g.nextPush.Sub(time.Now())) - p.Bot.Send(bot.Reply, message.Channel, msg, identifier) + p.bot.Send(c, bot.Reply, message.Channel, msg, identifier) } else { - p.Bot.Send(bot.Reply, message.Channel, "you lose", identifier) + p.bot.Send(c, bot.Reply, message.Channel, "you lose", identifier) msg := fmt.Sprintf("%s just lost the sisyphus game after %s", g.who, time.Now().Sub(g.start)) - p.Bot.Send(bot.Message, message.Channel, msg) + p.bot.Send(c, bot.Message, message.Channel, msg) g.endGame() } } else { - p.Bot.Send(bot.Reply, message.Channel, "you cannot push yet", identifier) + p.bot.Send(c, bot.Reply, message.Channel, "you cannot push yet", identifier) } return true } diff --git a/plugins/talker/talker.go b/plugins/talker/talker.go index 3bba94f..7dc6fa2 100644 --- a/plugins/talker/talker.go +++ b/plugins/talker/talker.go @@ -17,7 +17,7 @@ import ( "github.com/velour/catbase/config" ) -var goatse []string = []string{ +var goatse = []string{ "```* g o a t s e x * g o a t s e x * g o a t s e x *", "g g", "o / \\ \\ / \\ o", @@ -46,23 +46,23 @@ var goatse []string = []string{ } type TalkerPlugin struct { - Bot bot.Bot + bot bot.Bot config *config.Config sayings []string } func New(b bot.Bot) *TalkerPlugin { tp := &TalkerPlugin{ - Bot: b, + bot: b, config: b.Config(), } b.Register(tp, bot.Message, tp.message) b.Register(tp, bot.Help, tp.help) - tp.registerWeb() + tp.registerWeb(b.DefaultConnector()) return tp } -func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *TalkerPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { channel := message.Channel body := message.Body lowermessage := strings.ToLower(body) @@ -70,24 +70,24 @@ func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...inter if message.Command && strings.HasPrefix(lowermessage, "cowsay") { msg, err := p.cowSay(strings.TrimPrefix(message.Body, "cowsay ")) if err != nil { - p.Bot.Send(bot.Message, channel, "Error running cowsay: %s", err) + p.bot.Send(c, bot.Message, channel, "Error running cowsay: %s", err) return true } - p.Bot.Send(bot.Message, channel, msg) + p.bot.Send(c, bot.Message, channel, msg) return true } if message.Command && strings.HasPrefix(lowermessage, "list cows") { cows := p.allCows() m := fmt.Sprintf("Cows: %s", strings.Join(cows, ", ")) - p.Bot.Send(bot.Message, channel, m) + p.bot.Send(c, bot.Message, channel, m) return true } // TODO: This ought to be space split afterwards to remove any punctuation if message.Command && strings.HasPrefix(lowermessage, "say") { msg := strings.TrimSpace(body[3:]) - p.Bot.Send(bot.Message, channel, msg) + p.bot.Send(c, bot.Message, channel, msg) return true } @@ -103,15 +103,15 @@ func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...inter line = strings.Replace(line, "{nick}", nick, 1) output += line + "\n" } - p.Bot.Send(bot.Message, channel, output) + p.bot.Send(c, bot.Message, channel, output) return true } return false } -func (p *TalkerPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.Bot.Send(bot.Message, message.Channel, "Hi, this is talker. I like to talk about FredFelps!") +func (p *TalkerPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "Hi, this is talker. I like to talk about FredFelps!") return true } @@ -170,7 +170,7 @@ func (p *TalkerPlugin) allCows() []string { return cows } -func (p *TalkerPlugin) registerWeb() { +func (p *TalkerPlugin) registerWeb(c bot.Connector) { http.HandleFunc("/slash/cowsay", func(w http.ResponseWriter, r *http.Request) { r.ParseForm() log.Debug().Msgf("Cowsay:\n%+v", r.PostForm.Get("text")) @@ -178,10 +178,10 @@ func (p *TalkerPlugin) registerWeb() { log.Debug().Msgf("channel: %s", channel) msg, err := p.cowSay(r.PostForm.Get("text")) if err != nil { - p.Bot.Send(bot.Message, channel, fmt.Sprintf("Error running cowsay: %s", err)) + p.bot.Send(c, bot.Message, channel, fmt.Sprintf("Error running cowsay: %s", err)) return } - p.Bot.Send(bot.Message, channel, msg) + p.bot.Send(c, bot.Message, channel, msg) w.WriteHeader(200) }) } diff --git a/plugins/talker/talker_test.go b/plugins/talker/talker_test.go index fe65779..cf3defe 100644 --- a/plugins/talker/talker_test.go +++ b/plugins/talker/talker_test.go @@ -3,6 +3,7 @@ package talker import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, @@ -78,6 +79,6 @@ func TestHelp(t *testing.T) { mb := bot.NewMockBot() c := New(mb) assert.NotNil(t, c) - c.help(bot.Help, msg.Message{Channel: "channel"}, []string{}) + c.help(&cli.CliPlugin{}, bot.Help, msg.Message{Channel: "channel"}, []string{}) assert.Len(t, mb.Messages, 1) } diff --git a/plugins/tell/tell.go b/plugins/tell/tell.go index aba8410..a106574 100644 --- a/plugins/tell/tell.go +++ b/plugins/tell/tell.go @@ -21,20 +21,20 @@ func New(b bot.Bot) *TellPlugin { return tp } -func (t *TellPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (t *TellPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { if strings.HasPrefix(strings.ToLower(message.Body), "tell") { parts := strings.Split(message.Body, " ") target := strings.ToLower(parts[1]) newMessage := strings.Join(parts[2:], " ") newMessage = fmt.Sprintf("Hey, %s. %s said: %s", target, message.User.Name, newMessage) t.users[target] = append(t.users[target], newMessage) - t.b.Send(bot.Message, message.Channel, fmt.Sprintf("Okay. I'll tell %s.", target)) + t.b.Send(c, bot.Message, message.Channel, fmt.Sprintf("Okay. I'll tell %s.", target)) return true } uname := strings.ToLower(message.User.Name) if msg, ok := t.users[uname]; ok && len(msg) > 0 { for _, m := range msg { - t.b.Send(bot.Message, message.Channel, string(m)) + t.b.Send(c, bot.Message, message.Channel, string(m)) } t.users[uname] = []string{} return true diff --git a/plugins/tldr/tldr.go b/plugins/tldr/tldr.go index 617da40..0bc3caf 100644 --- a/plugins/tldr/tldr.go +++ b/plugins/tldr/tldr.go @@ -38,11 +38,11 @@ func New(b bot.Bot) *TLDRPlugin { return plugin } -func (p *TLDRPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *TLDRPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { timeLimit := time.Duration(p.bot.Config().GetInt("TLDR.HourLimit", 1)) lowercaseMessage := strings.ToLower(message.Body) if lowercaseMessage == "tl;dr" && p.lastRequest.After(time.Now().Add(-timeLimit*time.Hour)) { - p.bot.Send(bot.Message, message.Channel, "Slow down, cowboy. Read that tiny backlog.") + p.bot.Send(c, bot.Message, message.Channel, "Slow down, cowboy. Read that tiny backlog.") return true } else if lowercaseMessage == "tl;dr" { p.lastRequest = time.Now() @@ -114,7 +114,7 @@ func (p *TLDRPlugin) message(kind bot.Kind, message msg.Message, args ...interfa } - p.bot.Send(bot.Message, message.Channel, response) + p.bot.Send(c, bot.Message, message.Channel, response) return true } @@ -162,8 +162,8 @@ func (p *TLDRPlugin) getTopics() []string { } // Help responds to help requests. Every plugin must implement a help function. -func (p *TLDRPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.bot.Send(bot.Message, message.Channel, "tl;dr") +func (p *TLDRPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "tl;dr") return true } diff --git a/plugins/tldr/tldr_test.go b/plugins/tldr/tldr_test.go index 2bec842..4328463 100644 --- a/plugins/tldr/tldr_test.go +++ b/plugins/tldr/tldr_test.go @@ -1,6 +1,7 @@ package tldr import ( + "github.com/velour/catbase/plugins/cli" "os" "strconv" "strings" @@ -19,12 +20,12 @@ func init() { log.Logger = log.Logger.Output(zerolog.ConsoleWriter{Out: os.Stderr}) } -func makeMessageBy(payload, by string) (bot.Kind, msg.Message) { +func makeMessageBy(payload, by string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: by}, Channel: "test", Body: payload, @@ -32,7 +33,7 @@ func makeMessageBy(payload, by string) (bot.Kind, msg.Message) { } } -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { return makeMessageBy(payload, "tester") } diff --git a/plugins/twitch/twitch.go b/plugins/twitch/twitch.go index 37d8602..155fa9f 100644 --- a/plugins/twitch/twitch.go +++ b/plugins/twitch/twitch.go @@ -24,7 +24,7 @@ const ( ) type TwitchPlugin struct { - Bot bot.Bot + bot bot.Bot config *config.Config twitchList map[string]*Twitcher } @@ -60,7 +60,7 @@ type stream struct { func New(b bot.Bot) *TwitchPlugin { p := &TwitchPlugin{ - Bot: b, + bot: b, config: b.Config(), twitchList: map[string]*Twitcher{}, } @@ -74,7 +74,7 @@ func New(b bot.Bot) *TwitchPlugin { } } } - go p.twitchLoop(ch) + go p.twitchLoop(b.DefaultConnector(), ch) } b.Register(p, bot.Message, p.message) @@ -119,14 +119,14 @@ func (p *TwitchPlugin) serveStreaming(w http.ResponseWriter, r *http.Request) { } } -func (p *TwitchPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *TwitchPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { body := strings.ToLower(message.Body) if body == "twitch status" { channel := message.Channel if users := p.config.GetArray("Twitch."+channel+".Users", []string{}); len(users) > 0 { for _, twitcherName := range users { if _, ok := p.twitchList[twitcherName]; ok { - p.checkTwitch(channel, p.twitchList[twitcherName], true) + p.checkTwitch(c, channel, p.twitchList[twitcherName], true) } } } @@ -140,18 +140,18 @@ func (p *TwitchPlugin) message(kind bot.Kind, message msg.Message, args ...inter return false } -func (p *TwitchPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *TwitchPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { msg := "You can set the templates for streams with\n" msg += fmt.Sprintf("twitch.istpl (default: %s)\n", isStreamingTplFallback) msg += fmt.Sprintf("twitch.nottpl (default: %s)\n", notStreamingTplFallback) msg += fmt.Sprintf("twitch.stoppedtpl (default: %s)\n", stoppedStreamingTplFallback) msg += "You can reset all messages with `!reset twitch`" msg += "And you can ask who is streaming with `!twitch status`" - p.Bot.Send(bot.Message, message.Channel, msg) + p.bot.Send(c, bot.Message, message.Channel, msg) return true } -func (p *TwitchPlugin) twitchLoop(channel string) { +func (p *TwitchPlugin) twitchLoop(c bot.Connector, channel string) { frequency := p.config.GetInt("Twitch.Freq", 60) if p.config.Get("twitch.clientid", "") == "" || p.config.Get("twitch.authorization", "") == "" { log.Info().Msgf("Disabling twitch autochecking.") @@ -164,7 +164,7 @@ func (p *TwitchPlugin) twitchLoop(channel string) { time.Sleep(time.Duration(frequency) * time.Second) for _, twitcherName := range p.config.GetArray("Twitch."+channel+".Users", []string{}) { - p.checkTwitch(channel, p.twitchList[twitcherName], false) + p.checkTwitch(c, channel, p.twitchList[twitcherName], false) } } } @@ -197,7 +197,7 @@ errCase: return []byte{}, false } -func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPrintStatus bool) { +func (p *TwitchPlugin) checkTwitch(c bot.Connector, channel string, twitcher *Twitcher, alwaysPrintStatus bool) { baseURL, err := url.Parse("https://api.twitch.tv/helix/streams") if err != nil { log.Error().Msg("Error parsing twitch stream URL") @@ -255,31 +255,31 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri t, err := template.New("notStreaming").Parse(notStreamingTpl) if err != nil { log.Error().Err(err) - p.Bot.Send(bot.Message, channel, err) + p.bot.Send(c, bot.Message, channel, err) t = template.Must(template.New("notStreaming").Parse(notStreamingTplFallback)) } t.Execute(&buf, info) - p.Bot.Send(bot.Message, channel, buf.String()) + p.bot.Send(c, bot.Message, channel, buf.String()) } else { t, err := template.New("isStreaming").Parse(isStreamingTpl) if err != nil { log.Error().Err(err) - p.Bot.Send(bot.Message, channel, err) + p.bot.Send(c, bot.Message, channel, err) t = template.Must(template.New("isStreaming").Parse(isStreamingTplFallback)) } t.Execute(&buf, info) - p.Bot.Send(bot.Message, channel, buf.String()) + p.bot.Send(c, bot.Message, channel, buf.String()) } } else if gameID == "" { if twitcher.gameID != "" { t, err := template.New("stoppedStreaming").Parse(stoppedStreamingTpl) if err != nil { log.Error().Err(err) - p.Bot.Send(bot.Message, channel, err) + p.bot.Send(c, bot.Message, channel, err) t = template.Must(template.New("stoppedStreaming").Parse(stoppedStreamingTplFallback)) } t.Execute(&buf, info) - p.Bot.Send(bot.Message, channel, buf.String()) + p.bot.Send(c, bot.Message, channel, buf.String()) } twitcher.gameID = "" } else { @@ -287,11 +287,11 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri t, err := template.New("isStreaming").Parse(isStreamingTpl) if err != nil { log.Error().Err(err) - p.Bot.Send(bot.Message, channel, err) + p.bot.Send(c, bot.Message, channel, err) t = template.Must(template.New("isStreaming").Parse(isStreamingTplFallback)) } t.Execute(&buf, info) - p.Bot.Send(bot.Message, channel, buf.String()) + p.bot.Send(c, bot.Message, channel, buf.String()) } twitcher.gameID = gameID } diff --git a/plugins/twitch/twitch_test.go b/plugins/twitch/twitch_test.go index 120defa..1defec5 100644 --- a/plugins/twitch/twitch_test.go +++ b/plugins/twitch/twitch_test.go @@ -3,6 +3,7 @@ package twitch import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/your/your.go b/plugins/your/your.go index 1d26e9d..10dfc2b 100644 --- a/plugins/your/your.go +++ b/plugins/your/your.go @@ -30,7 +30,7 @@ func New(b bot.Bot) *YourPlugin { // 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 *YourPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *YourPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { maxLen := p.config.GetInt("your.maxlength", 140) if len(message.Body) > maxLen { return false @@ -46,14 +46,14 @@ func (p *YourPlugin) message(kind bot.Kind, message msg.Message, args ...interfa } } if msg != message.Body { - p.bot.Send(bot.Message, message.Channel, msg) + p.bot.Send(c, bot.Message, message.Channel, msg) return true } return false } // Help responds to help requests. Every plugin must implement a help function. -func (p *YourPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.bot.Send(bot.Message, message.Channel, "Your corrects people's grammar.") +func (p *YourPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "Your corrects people's grammar.") return true } diff --git a/plugins/your/your_test.go b/plugins/your/your_test.go index 3c6136a..ea13638 100644 --- a/plugins/your/your_test.go +++ b/plugins/your/your_test.go @@ -3,6 +3,7 @@ package your import ( + "github.com/velour/catbase/plugins/cli" "strings" "testing" @@ -12,12 +13,12 @@ import ( "github.com/velour/catbase/bot/user" ) -func makeMessage(payload string) (bot.Kind, msg.Message) { +func makeMessage(payload string) (bot.Connector, bot.Kind, msg.Message) { isCmd := strings.HasPrefix(payload, "!") if isCmd { payload = payload[1:] } - return bot.Message, msg.Message{ + return &cli.CliPlugin{}, bot.Message, msg.Message{ User: &user.User{Name: "tester"}, Channel: "test", Body: payload, diff --git a/plugins/zork/zork.go b/plugins/zork/zork.go index 95da698..11458a7 100644 --- a/plugins/zork/zork.go +++ b/plugins/zork/zork.go @@ -37,7 +37,7 @@ func New(b bot.Bot) bot.Plugin { return z } -func (p *ZorkPlugin) runZork(ch string) error { +func (p *ZorkPlugin) runZork(c bot.Connector, ch string) error { const importString = "github.com/velour/catbase/plugins/zork" pkg, err := build.Import(importString, "", build.FindOnly) if err != nil { @@ -79,7 +79,7 @@ func (p *ZorkPlugin) runZork(ch string) error { m := strings.Replace(s.Text(), ">", "", -1) m = strings.Replace(m, "\n", "\n>", -1) m = ">" + m + "\n" - p.bot.Send(bot.Message, ch, m) + p.bot.Send(c, bot.Message, ch, m) } }() go func() { @@ -95,7 +95,7 @@ func (p *ZorkPlugin) runZork(ch string) error { return nil } -func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool { +func (p *ZorkPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { m := strings.ToLower(message.Body) log.Debug().Msgf("got message [%s]", m) if ts := strings.Fields(m); len(ts) < 1 || ts[0] != "zork" { @@ -107,8 +107,8 @@ func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interfa p.Lock() defer p.Unlock() if p.zorks[ch] == nil { - if err := p.runZork(ch); err != nil { - p.bot.Send(bot.Message, ch, "failed to run zork: "+err.Error()) + if err := p.runZork(c, ch); err != nil { + p.bot.Send(c, bot.Message, ch, "failed to run zork: "+err.Error()) return true } } @@ -117,7 +117,7 @@ func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interfa return true } -func (p *ZorkPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool { - p.bot.Send(bot.Message, message.Channel, "Play zork using 'zork '.") +func (p *ZorkPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool { + p.bot.Send(c, bot.Message, message.Channel, "Play zork using 'zork '.") return true }