Merge pull request #141 from velour/events

Strict Interfaces => Events
This commit is contained in:
Chris Sexton 2019-02-05 16:27:08 -05:00 committed by GitHub
commit b11815dec3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 866 additions and 1155 deletions

View File

@ -6,6 +6,7 @@ import (
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
"reflect"
"strings" "strings"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -19,7 +20,7 @@ import (
type bot struct { type bot struct {
// Each plugin must be registered in our plugins handler. To come: a map so that this // Each plugin must be registered in our plugins handler. To come: a map so that this
// will allow plugins to respond to specific kinds of events // will allow plugins to respond to specific kinds of events
plugins map[string]Handler plugins map[string]Plugin
pluginOrdering []string pluginOrdering []string
// Users holds information about all of our friends // Users holds information about all of our friends
@ -41,13 +42,16 @@ type bot struct {
// filters registered by plugins // filters registered by plugins
filters map[string]func(string) string filters map[string]func(string) string
callbacks CallbackMap
} }
// Variable represents a $var replacement
type Variable struct { type Variable struct {
Variable, Value string Variable, Value string
} }
// Newbot creates a bot for a given connection and set of handlers. // New creates a bot for a given connection and set of handlers.
func New(config *config.Config, connector Connector) Bot { func New(config *config.Config, connector Connector) Bot {
logIn := make(chan msg.Message) logIn := make(chan msg.Message)
logOut := make(chan msg.Messages) logOut := make(chan msg.Messages)
@ -62,7 +66,7 @@ func New(config *config.Config, connector Connector) Bot {
bot := &bot{ bot := &bot{
config: config, config: config,
plugins: make(map[string]Handler), plugins: make(map[string]Plugin),
pluginOrdering: make([]string, 0), pluginOrdering: make([]string, 0),
conn: connector, conn: connector,
users: users, users: users,
@ -71,6 +75,7 @@ func New(config *config.Config, connector Connector) Bot {
logOut: logOut, logOut: logOut,
httpEndPoints: make(map[string]string), httpEndPoints: make(map[string]string),
filters: make(map[string]func(string) string), filters: make(map[string]func(string) string),
callbacks: make(CallbackMap),
} }
bot.migrateDB() bot.migrateDB()
@ -79,9 +84,7 @@ func New(config *config.Config, connector Connector) Bot {
addr := config.Get("HttpAddr", "127.0.0.1:1337") addr := config.Get("HttpAddr", "127.0.0.1:1337")
go http.ListenAndServe(addr, nil) go http.ListenAndServe(addr, nil)
connector.RegisterMessageReceived(bot.MsgReceived) connector.RegisterEvent(bot.Receive)
connector.RegisterEventReceived(bot.EventReceived)
connector.RegisterReplyMessageReceived(bot.ReplyMsgReceived)
return bot return bot
} }
@ -109,7 +112,8 @@ func (b *bot) migrateDB() {
} }
// Adds a constructed handler to the bots handlers list // Adds a constructed handler to the bots handlers list
func (b *bot) AddHandler(name string, h Handler) { func (b *bot) AddPlugin(h Plugin) {
name := reflect.TypeOf(h).String()
b.plugins[name] = h b.plugins[name] = h
b.pluginOrdering = append(b.pluginOrdering, name) b.pluginOrdering = append(b.pluginOrdering, name)
if entry := h.RegisterWeb(); entry != nil { if entry := h.RegisterWeb(); entry != nil {
@ -126,7 +130,7 @@ func (b *bot) Who(channel string) []user.User {
return users return users
} }
var rootIndex string = ` var rootIndex = `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
@ -166,7 +170,7 @@ func (b *bot) serveRoot(w http.ResponseWriter, r *http.Request) {
t.Execute(w, context) t.Execute(w, context)
} }
// Checks if message is a command and returns its curtailed version // IsCmd checks if message is a command and returns its curtailed version
func IsCmd(c *config.Config, message string) (bool, string) { func IsCmd(c *config.Config, message string) (bool, string) {
cmdcs := c.GetArray("CommandChar", []string{"!"}) cmdcs := c.GetArray("CommandChar", []string{"!"})
botnick := strings.ToLower(c.Get("Nick", "bot")) botnick := strings.ToLower(c.Get("Nick", "bot"))
@ -244,3 +248,15 @@ func (b *bot) checkAdmin(nick string) bool {
func (b *bot) RegisterFilter(name string, f func(string) string) { func (b *bot) RegisterFilter(name string, f func(string) string) {
b.filters[name] = f b.filters[name] = f
} }
// Register a callback
func (b *bot) Register(p Plugin, kind Kind, cb Callback) {
t := reflect.TypeOf(p)
if _, ok := b.callbacks[t]; !ok {
b.callbacks[t] = make(map[Kind][]Callback)
}
if _, ok := b.callbacks[t][kind]; !ok {
b.callbacks[t][kind] = []Callback{}
}
b.callbacks[t][kind] = append(b.callbacks[t][kind], cb)
}

View File

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"log" "log"
"math/rand" "math/rand"
"reflect"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -16,22 +17,20 @@ import (
"github.com/velour/catbase/bot/msg" "github.com/velour/catbase/bot/msg"
) )
// Handles incomming PRIVMSG requests func (b *bot) Receive(kind Kind, msg msg.Message, args ...interface{}) {
func (b *bot) MsgReceived(msg msg.Message) { log.Println("Received event: ", msg)
log.Println("Received message: ", msg)
// msg := b.buildMessage(client, inMsg) // msg := b.buildMessage(client, inMsg)
// do need to look up user and fix it // do need to look up user and fix it
if strings.HasPrefix(msg.Body, "help ") && msg.Command { if kind == Message && strings.HasPrefix(msg.Body, "help ") && msg.Command {
parts := strings.Fields(strings.ToLower(msg.Body)) parts := strings.Fields(strings.ToLower(msg.Body))
b.checkHelp(msg.Channel, parts) b.checkHelp(msg.Channel, parts)
goto RET goto RET
} }
for _, name := range b.pluginOrdering { for _, name := range b.pluginOrdering {
p := b.plugins[name] if b.runCallback(b.plugins[name], kind, msg, args...) {
if p.Message(msg) { goto RET
break
} }
} }
@ -40,52 +39,19 @@ RET:
return return
} }
// Handle incoming events func (b *bot) runCallback(plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
func (b *bot) EventReceived(msg msg.Message) { t := reflect.TypeOf(plugin)
log.Println("Received event: ", msg) for _, cb := range b.callbacks[t][evt] {
//msg := b.buildMessage(conn, inMsg) if cb(evt, message, args...) {
for _, name := range b.pluginOrdering { return true
p := b.plugins[name]
if p.Event(msg.Body, msg) { // TODO: could get rid of msg.Body
break
} }
} }
return false
} }
// Handle incoming replys // Send a message to the connection
func (b *bot) ReplyMsgReceived(msg msg.Message, identifier string) { func (b *bot) Send(kind Kind, args ...interface{}) (string, error) {
log.Println("Received message: ", msg) return b.conn.Send(kind, args...)
for _, name := range b.pluginOrdering {
p := b.plugins[name]
if p.ReplyMessage(msg, identifier) {
break
}
}
}
func (b *bot) SendMessage(channel, message string) string {
return b.conn.SendMessage(channel, message)
}
func (b *bot) SendAction(channel, message string) string {
return b.conn.SendAction(channel, message)
}
func (b *bot) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) {
return b.conn.ReplyToMessageIdentifier(channel, message, identifier)
}
func (b *bot) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) {
return b.conn.ReplyToMessage(channel, message, replyTo)
}
func (b *bot) React(channel, reaction string, message msg.Message) bool {
return b.conn.React(channel, reaction, message)
}
func (b *bot) Edit(channel, newMessage, identifier string) bool {
return b.conn.Edit(channel, newMessage, identifier)
} }
func (b *bot) GetEmojiList() map[string]string { func (b *bot) GetEmojiList() map[string]string {
@ -100,7 +66,7 @@ func (b *bot) checkHelp(channel string, parts []string) {
for name, _ := range b.plugins { for name, _ := range b.plugins {
topics = fmt.Sprintf("%s, %s", topics, name) topics = fmt.Sprintf("%s, %s", topics, name)
} }
b.SendMessage(channel, topics) b.Send(Message, channel, topics)
} else { } else {
// trigger the proper plugin's help response // trigger the proper plugin's help response
if parts[1] == "about" { if parts[1] == "about" {
@ -111,12 +77,12 @@ func (b *bot) checkHelp(channel string, parts []string) {
b.listVars(channel, parts) b.listVars(channel, parts)
return return
} }
plugin := b.plugins[parts[1]] plugin, ok := b.plugins[parts[1]]
if plugin != nil { if ok {
plugin.Help(channel, parts) b.runCallback(plugin, Help, msg.Message{Channel: channel}, channel, parts)
} else { } else {
msg := fmt.Sprintf("I'm sorry, I don't know what %s is!", parts[1]) msg := fmt.Sprintf("I'm sorry, I don't know what %s is!", parts[1])
b.SendMessage(channel, msg) b.Send(Message, channel, msg)
} }
} }
} }
@ -212,14 +178,14 @@ func (b *bot) listVars(channel string, parts []string) {
if len(variables) > 0 { if len(variables) > 0 {
msg += ", " + strings.Join(variables, ", ") msg += ", " + strings.Join(variables, ", ")
} }
b.SendMessage(channel, msg) b.Send(Message, channel, msg)
} }
func (b *bot) Help(channel string, parts []string) { func (b *bot) Help(channel string, parts []string) {
msg := fmt.Sprintf("Hi, I'm based on godeepintir version %s. I'm written in Go, and you "+ 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: "+ "can find my source code on the internet here: "+
"http://github.com/velour/catbase", b.version) "http://github.com/velour/catbase", b.version)
b.SendMessage(channel, msg) b.Send(Message, channel, msg)
} }
// Send our own musings to the plugins // Send our own musings to the plugins
@ -236,9 +202,8 @@ func (b *bot) selfSaid(channel, message string, action bool) {
} }
for _, name := range b.pluginOrdering { for _, name := range b.pluginOrdering {
p := b.plugins[name] if b.runCallback(b.plugins[name], SelfMessage, msg) {
if p.BotMessage(msg) { return
break
} }
} }
} }

View File

@ -3,56 +3,78 @@
package bot package bot
import ( import (
"reflect"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot/msg" "github.com/velour/catbase/bot/msg"
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
"github.com/velour/catbase/config" "github.com/velour/catbase/config"
) )
const (
_ = iota
// Message any standard chat
Message
// Reply something containing a message reference
Reply
// Action any /me action
Action
// Reaction Icon reaction if service supports it
Reaction
// Edit message ref'd new message to replace
Edit
// Not sure what event is
Event
// Help is used when the bot help system is triggered
Help
// SelfMessage triggers when the bot is sending a message
SelfMessage
)
type Kind int
type Callback func(Kind, msg.Message, ...interface{}) bool
type CallbackMap map[reflect.Type]map[Kind][]Callback
// Bot interface serves to allow mocking of the actual bot
type Bot interface { type Bot interface {
// Config allows access to the bot's configuration system
Config() *config.Config Config() *config.Config
// DB gives access to the current database
DB() *sqlx.DB DB() *sqlx.DB
// Who lists users in a particular channel
Who(string) []user.User Who(string) []user.User
AddHandler(string, Handler) // AddPlugin registers a new plugin handler
SendMessage(string, string) string AddPlugin(Plugin)
SendAction(string, string) string // First arg should be one of bot.Message/Reply/Action/etc
ReplyToMessageIdentifier(string, string, string) (string, bool) Send(Kind, ...interface{}) (string, error)
ReplyToMessage(string, string, msg.Message) (string, bool) // First arg should be one of bot.Message/Reply/Action/etc
React(string, string, msg.Message) bool Receive(Kind, msg.Message, ...interface{})
Edit(string, string, string) bool // Register a callback
MsgReceived(msg.Message) Register(Plugin, Kind, Callback)
ReplyMsgReceived(msg.Message, string)
EventReceived(msg.Message)
Filter(msg.Message, string) string Filter(msg.Message, string) string
LastMessage(string) (msg.Message, error) LastMessage(string) (msg.Message, error)
CheckAdmin(string) bool CheckAdmin(string) bool
GetEmojiList() map[string]string GetEmojiList() map[string]string
RegisterFilter(string, func(string) string) RegisterFilter(string, func(string) string)
} }
// Connector represents a server connection to a chat service
type Connector interface { type Connector interface {
RegisterEventReceived(func(message msg.Message)) RegisterEvent(func(Kind, msg.Message, ...interface{}))
RegisterMessageReceived(func(message msg.Message))
RegisterReplyMessageReceived(func(msg.Message, string)) Send(Kind, ...interface{}) (string, error)
SendMessage(channel, message string) string
SendAction(channel, message string) string
ReplyToMessageIdentifier(string, string, string) (string, bool)
ReplyToMessage(string, string, msg.Message) (string, bool)
React(string, string, msg.Message) bool
Edit(string, string, string) bool
GetEmojiList() map[string]string GetEmojiList() map[string]string
Serve() error Serve() error
Who(string) []string Who(string) []string
} }
// Interface used for compatibility with the Plugin interface // Plugin interface used for compatibility with the Plugin interface
type Handler interface { // Probably can disappear once RegisterWeb gets inverted
Message(message msg.Message) bool type Plugin interface {
Event(kind string, message msg.Message) bool
ReplyMessage(msg.Message, string) bool
BotMessage(message msg.Message) bool
Help(channel string, parts []string)
RegisterWeb() *string RegisterWeb() *string
} }

View File

@ -27,67 +27,66 @@ type MockBot struct {
} }
func (mb *MockBot) Config() *config.Config { return mb.Cfg } func (mb *MockBot) Config() *config.Config { return mb.Cfg }
func (mb *MockBot) DBVersion() int64 { return 1 }
func (mb *MockBot) DB() *sqlx.DB { return mb.Cfg.DB } func (mb *MockBot) DB() *sqlx.DB { return mb.Cfg.DB }
func (mb *MockBot) Conn() Connector { return nil }
func (mb *MockBot) Who(string) []user.User { return []user.User{} } func (mb *MockBot) Who(string) []user.User { return []user.User{} }
func (mb *MockBot) AddHandler(name string, f Handler) {} func (mb *MockBot) Send(kind Kind, args ...interface{}) (string, error) {
func (mb *MockBot) SendMessage(ch string, msg string) string { switch kind {
mb.Messages = append(mb.Messages, msg) case Message:
return fmt.Sprintf("m-%d", len(mb.Actions)-1) mb.Messages = append(mb.Messages, args[1].(string))
return fmt.Sprintf("m-%d", len(mb.Actions)-1), nil
case Action:
mb.Actions = append(mb.Actions, args[1].(string))
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)
case Reaction:
ch, re, msg := args[0].(string), args[1].(string), args[2].(msg.Message)
return mb.react(ch, re, msg)
}
return "ERR", fmt.Errorf("Mesasge type unhandled")
} }
func (mb *MockBot) SendAction(ch string, msg string) string { func (mb *MockBot) AddPlugin(f Plugin) {}
mb.Actions = append(mb.Actions, msg) func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {}
return fmt.Sprintf("a-%d", len(mb.Actions)-1) func (mb *MockBot) Receive(kind Kind, msg msg.Message, args ...interface{}) {}
}
func (mb *MockBot) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) {
return "", false
}
func (mb *MockBot) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) {
return "", false
}
func (mb *MockBot) MsgReceived(msg msg.Message) {}
func (mb *MockBot) EventReceived(msg msg.Message) {}
func (mb *MockBot) Filter(msg msg.Message, s string) string { return s } 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) LastMessage(ch string) (msg.Message, error) { return msg.Message{}, nil }
func (mb *MockBot) CheckAdmin(nick string) bool { return false } func (mb *MockBot) CheckAdmin(nick string) bool { return false }
func (mb *MockBot) React(channel, reaction string, message msg.Message) bool { func (mb *MockBot) react(channel, reaction string, message msg.Message) (string, error) {
mb.Reactions = append(mb.Reactions, reaction) mb.Reactions = append(mb.Reactions, reaction)
return false return "", nil
} }
func (mb *MockBot) Edit(channel, newMessage, identifier string) bool { func (mb *MockBot) edit(channel, newMessage, identifier string) (string, error) {
isMessage := identifier[0] == 'm' isMessage := identifier[0] == 'm'
if !isMessage && identifier[0] != 'a' { if !isMessage && identifier[0] != 'a' {
log.Printf("failed to parse identifier: %s", identifier) err := fmt.Errorf("failed to parse identifier: %s", identifier)
return false log.Println(err)
return "", err
} }
index, err := strconv.Atoi(strings.Split(identifier, "-")[1]) index, err := strconv.Atoi(strings.Split(identifier, "-")[1])
if err != nil { if err != nil {
log.Printf("failed to parse identifier: %s", identifier) err := fmt.Errorf("failed to parse identifier: %s", identifier)
return false log.Println(err)
return "", err
} }
if isMessage { if isMessage {
if index < len(mb.Messages) { if index < len(mb.Messages) {
mb.Messages[index] = newMessage mb.Messages[index] = newMessage
} else { } else {
return false return "", fmt.Errorf("No message")
} }
} else { } else {
if index < len(mb.Actions) { if index < len(mb.Actions) {
mb.Actions[index] = newMessage mb.Actions[index] = newMessage
} else { } else {
return false return "", fmt.Errorf("No action")
} }
} }
return true return "", nil
}
func (mb *MockBot) ReplyMsgReceived(msg.Message, string) {
} }
func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) } func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) }

8
go.mod
View File

@ -5,21 +5,21 @@ require (
github.com/boltdb/bolt v1.3.1 github.com/boltdb/bolt v1.3.1
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/gorilla/websocket v1.4.0 // indirect github.com/gorilla/websocket v1.4.0 // indirect
github.com/jmoiron/sqlx v1.2.0 github.com/jmoiron/sqlx v1.2.0
github.com/mattn/go-sqlite3 v1.10.0 github.com/mattn/go-sqlite3 v1.10.0
github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/mmcdole/gofeed v1.0.0-beta2 github.com/mmcdole/gofeed v1.0.0-beta2
github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf // indirect github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d // indirect github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d // indirect
github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.2.2 github.com/stretchr/testify v1.3.0
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89 github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158 github.com/velour/velour v0.0.0-20160303155839-8e090e68d158
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7
github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec github.com/yuin/gopher-lua v0.0.0-20190125051437-7b9317363aa9
golang.org/x/net v0.0.0-20181217023233-e147a9138326 // indirect golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect
golang.org/x/text v0.3.0 // indirect golang.org/x/text v0.3.0 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect
) )

8
go.sum
View File

@ -7,9 +7,11 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA= github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA=
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff/go.mod h1:QCRjR0b4qiJiNjuP7RFM89bh4UExGJalcWmYeSvlnRc= github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff/go.mod h1:QCRjR0b4qiJiNjuP7RFM89bh4UExGJalcWmYeSvlnRc=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
@ -28,10 +30,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4=
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89 h1:3D3M900hEBJJAqyKl70QuRHi5weX9+ptlQI1v+FNcQ8= github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89 h1:3D3M900hEBJJAqyKl70QuRHi5weX9+ptlQI1v+FNcQ8=
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89/go.mod h1:ejwOYCjnDMyO5LXFXRARQJGBZ6xQJZ3rgAHE5drSuMM= github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89/go.mod h1:ejwOYCjnDMyO5LXFXRARQJGBZ6xQJZ3rgAHE5drSuMM=
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158 h1:p3rTUXxzuKsBOsHlkly7+rj9wagFBKeIsCDKkDII9sw= github.com/velour/velour v0.0.0-20160303155839-8e090e68d158 h1:p3rTUXxzuKsBOsHlkly7+rj9wagFBKeIsCDKkDII9sw=
@ -40,10 +45,13 @@ github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38D
github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8= github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8=
github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec h1:vpF8Kxql6/3OvGH4y2SKtpN3WsB17mvJ8f8H1o2vucQ= github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec h1:vpF8Kxql6/3OvGH4y2SKtpN3WsB17mvJ8f8H1o2vucQ=
github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec/go.mod h1:fFiAh+CowNFr0NK5VASokuwKwkbacRmHsVA7Yb1Tqac= github.com/yuin/gopher-lua v0.0.0-20181214045814-db9ae37725ec/go.mod h1:fFiAh+CowNFr0NK5VASokuwKwkbacRmHsVA7Yb1Tqac=
github.com/yuin/gopher-lua v0.0.0-20190125051437-7b9317363aa9/go.mod h1:fFiAh+CowNFr0NK5VASokuwKwkbacRmHsVA7Yb1Tqac=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181217023233-e147a9138326 h1:iCzOf0xz39Tstp+Tu/WwyGjUXCk34QhQORRxBeXXTA4= golang.org/x/net v0.0.0-20181217023233-e147a9138326 h1:iCzOf0xz39Tstp+Tu/WwyGjUXCk34QhQORRxBeXXTA4=
golang.org/x/net v0.0.0-20181217023233-e147a9138326/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181217023233-e147a9138326/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 h1:ulvT7fqt0yHWzpJwI57MezWnYDVpCAYBVuYst/L+fAY=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=

View File

@ -42,9 +42,7 @@ type Irc struct {
config *config.Config config *config.Config
quit chan bool quit chan bool
eventReceived func(msg.Message) event func(bot.Kind, msg.Message, ...interface{})
messageReceived func(msg.Message)
replyMessageReceived func(msg.Message, string)
} }
func New(c *config.Config) *Irc { func New(c *config.Config) *Irc {
@ -54,16 +52,20 @@ func New(c *config.Config) *Irc {
return &i return &i
} }
func (i *Irc) RegisterEventReceived(f func(msg.Message)) { func (i *Irc) RegisterEvent(f func(bot.Kind, msg.Message, ...interface{})) {
i.eventReceived = f i.event = f
} }
func (i *Irc) RegisterMessageReceived(f func(msg.Message)) { func (i *Irc) Send(kind bot.Kind, args ...interface{}) (string, error) {
i.messageReceived = f switch kind {
} case bot.Reply:
case bot.Message:
func (i *Irc) RegisterReplyMessageReceived(f func(msg.Message, string)) { return i.sendMessage(args[0].(string), args[1].(string))
i.replyMessageReceived = f case bot.Action:
return i.sendAction(args[0].(string), args[1].(string))
default:
}
return "", nil
} }
func (i *Irc) JoinChannel(channel string) { func (i *Irc) JoinChannel(channel string) {
@ -71,7 +73,7 @@ func (i *Irc) JoinChannel(channel string) {
i.Client.Out <- irc.Msg{Cmd: irc.JOIN, Args: []string{channel}} i.Client.Out <- irc.Msg{Cmd: irc.JOIN, Args: []string{channel}}
} }
func (i *Irc) SendMessage(channel, message string) string { func (i *Irc) sendMessage(channel, message string) (string, error) {
for len(message) > 0 { for len(message) > 0 {
m := irc.Msg{ m := irc.Msg{
Cmd: "PRIVMSG", Cmd: "PRIVMSG",
@ -95,42 +97,23 @@ func (i *Irc) SendMessage(channel, message string) string {
i.Client.Out <- m i.Client.Out <- m
} }
return "NO_IRC_IDENTIFIERS" return "NO_IRC_IDENTIFIERS", nil
} }
// Sends action to channel // Sends action to channel
func (i *Irc) SendAction(channel, message string) string { func (i *Irc) sendAction(channel, message string) (string, error) {
message = actionPrefix + " " + message + "\x01" message = actionPrefix + " " + message + "\x01"
i.SendMessage(channel, message) return i.sendMessage(channel, message)
return "NO_IRC_IDENTIFIERS"
}
func (i *Irc) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) {
return "NO_IRC_IDENTIFIERS", false
}
func (i *Irc) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) {
return "NO_IRC_IDENTIFIERS", false
}
func (i *Irc) React(channel, reaction string, message msg.Message) bool {
//we're not goign to do anything because it's IRC
return false
}
func (i *Irc) Edit(channel, newMessage, identifier string) bool {
//we're not goign to do anything because it's IRC
return false
} }
func (i *Irc) GetEmojiList() map[string]string { func (i *Irc) GetEmojiList() map[string]string {
//we're not goign to do anything because it's IRC //we're not going to do anything because it's IRC
return make(map[string]string) return make(map[string]string)
} }
func (i *Irc) Serve() error { func (i *Irc) Serve() error {
if i.eventReceived == nil || i.messageReceived == nil { if i.event == nil {
return fmt.Errorf("Missing an event handler") return fmt.Errorf("Missing an event handler")
} }
@ -209,53 +192,53 @@ func (i *Irc) handleMsg(msg irc.Msg) {
// OK, ignore // OK, ignore
case irc.ERR_NOSUCHNICK: case irc.ERR_NOSUCHNICK:
i.eventReceived(botMsg) fallthrough
case irc.ERR_NOSUCHCHANNEL: case irc.ERR_NOSUCHCHANNEL:
i.eventReceived(botMsg) fallthrough
case irc.RPL_MOTD: case irc.RPL_MOTD:
i.eventReceived(botMsg) fallthrough
case irc.RPL_NAMREPLY: case irc.RPL_NAMREPLY:
i.eventReceived(botMsg) fallthrough
case irc.RPL_TOPIC: case irc.RPL_TOPIC:
i.eventReceived(botMsg) fallthrough
case irc.KICK: case irc.KICK:
i.eventReceived(botMsg) fallthrough
case irc.TOPIC: case irc.TOPIC:
i.eventReceived(botMsg) fallthrough
case irc.MODE: case irc.MODE:
i.eventReceived(botMsg) fallthrough
case irc.JOIN: case irc.JOIN:
i.eventReceived(botMsg) fallthrough
case irc.PART: case irc.PART:
i.eventReceived(botMsg) fallthrough
case irc.NOTICE:
fallthrough
case irc.NICK:
fallthrough
case irc.RPL_WHOREPLY:
fallthrough
case irc.RPL_ENDOFWHO:
i.event(bot.Event, botMsg)
case irc.PRIVMSG:
i.event(bot.Message, botMsg)
case irc.QUIT: case irc.QUIT:
os.Exit(1) os.Exit(1)
case irc.NOTICE:
i.eventReceived(botMsg)
case irc.PRIVMSG:
i.messageReceived(botMsg)
case irc.NICK:
i.eventReceived(botMsg)
case irc.RPL_WHOREPLY:
i.eventReceived(botMsg)
case irc.RPL_ENDOFWHO:
i.eventReceived(botMsg)
default: default:
cmd := irc.CmdNames[msg.Cmd] cmd := irc.CmdNames[msg.Cmd]
log.Println("(" + cmd + ") " + msg.Raw) log.Println("(" + cmd + ") " + msg.Raw)

50
main.go
View File

@ -78,32 +78,32 @@ func main() {
b := bot.New(c, client) b := bot.New(c, client)
b.AddHandler("admin", admin.New(b)) b.AddPlugin(admin.New(b))
b.AddHandler("first", first.New(b)) b.AddPlugin(emojifyme.New(b))
b.AddHandler("leftpad", leftpad.New(b)) b.AddPlugin(first.New(b))
b.AddHandler("talker", talker.New(b)) b.AddPlugin(leftpad.New(b))
b.AddHandler("dice", dice.New(b)) b.AddPlugin(talker.New(b))
b.AddHandler("picker", picker.New(b)) b.AddPlugin(dice.New(b))
b.AddHandler("beers", beers.New(b)) b.AddPlugin(picker.New(b))
b.AddHandler("remember", fact.NewRemember(b)) b.AddPlugin(beers.New(b))
b.AddHandler("your", your.New(b)) b.AddPlugin(fact.NewRemember(b))
b.AddHandler("counter", counter.New(b)) b.AddPlugin(your.New(b))
b.AddHandler("reminder", reminder.New(b)) b.AddPlugin(counter.New(b))
b.AddHandler("babbler", babbler.New(b)) b.AddPlugin(reminder.New(b))
b.AddHandler("zork", zork.New(b)) b.AddPlugin(babbler.New(b))
b.AddHandler("rss", rss.New(b)) b.AddPlugin(zork.New(b))
b.AddHandler("reaction", reaction.New(b)) b.AddPlugin(rss.New(b))
b.AddHandler("emojifyme", emojifyme.New(b)) b.AddPlugin(reaction.New(b))
b.AddHandler("twitch", twitch.New(b)) b.AddPlugin(twitch.New(b))
b.AddHandler("inventory", inventory.New(b)) b.AddPlugin(inventory.New(b))
b.AddHandler("rpgORdie", rpgORdie.New(b)) b.AddPlugin(rpgORdie.New(b))
b.AddHandler("sisyphus", sisyphus.New(b)) b.AddPlugin(sisyphus.New(b))
b.AddHandler("tell", tell.New(b)) b.AddPlugin(tell.New(b))
b.AddHandler("couldashouldawoulda", couldashouldawoulda.New(b)) b.AddPlugin(couldashouldawoulda.New(b))
b.AddHandler("nedepedia", nerdepedia.New(b)) b.AddPlugin(nerdepedia.New(b))
// catches anything left, will always return true // catches anything left, will always return true
b.AddHandler("factoid", fact.New(b)) b.AddPlugin(fact.New(b))
b.AddHandler("db", db.New(b)) b.AddPlugin(db.New(b))
for { for {
err := client.Serve() err := client.Serve()

View File

@ -25,12 +25,14 @@ type AdminPlugin struct {
} }
// NewAdminPlugin creates a new AdminPlugin with the Plugin interface // NewAdminPlugin creates a new AdminPlugin with the Plugin interface
func New(bot bot.Bot) *AdminPlugin { func New(b bot.Bot) *AdminPlugin {
p := &AdminPlugin{ p := &AdminPlugin{
Bot: bot, Bot: b,
db: bot.DB(), db: b.DB(),
cfg: bot.Config(), cfg: b.Config(),
} }
b.Register(p, bot.Message, p.message)
b.Register(p, bot.Help, p.help)
return p return p
} }
@ -44,7 +46,7 @@ var forbiddenKeys = map[string]bool{
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *AdminPlugin) Message(message msg.Message) bool { func (p *AdminPlugin) message(k bot.Kind, message msg.Message, args ...interface{}) bool {
body := message.Body body := message.Body
if p.quiet { if p.quiet {
@ -62,7 +64,7 @@ func (p *AdminPlugin) Message(message msg.Message) bool {
if strings.ToLower(body) == "shut up" { if strings.ToLower(body) == "shut up" {
dur := time.Duration(p.cfg.GetInt("quietDuration", 5)) * time.Minute dur := time.Duration(p.cfg.GetInt("quietDuration", 5)) * time.Minute
log.Printf("Going to sleep for %v, %v", dur, time.Now().Add(dur)) log.Printf("Going to sleep for %v, %v", dur, time.Now().Add(dur))
p.Bot.SendMessage(message.Channel, "Okay. I'll be back later.") p.Bot.Send(bot.Message, message.Channel, "Okay. I'll be back later.")
p.quiet = true p.quiet = true
go func() { go func() {
select { select {
@ -76,19 +78,19 @@ func (p *AdminPlugin) Message(message msg.Message) bool {
parts := strings.Split(body, " ") parts := strings.Split(body, " ")
if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] { if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] {
p.Bot.SendMessage(message.Channel, "You cannot access that key") p.Bot.Send(bot.Message, message.Channel, "You cannot access that key")
return true return true
} else if parts[0] == "set" && len(parts) > 2 { } else if parts[0] == "set" && len(parts) > 2 {
p.cfg.Set(parts[1], strings.Join(parts[2:], " ")) p.cfg.Set(parts[1], strings.Join(parts[2:], " "))
p.Bot.SendMessage(message.Channel, fmt.Sprintf("Set %s", parts[1])) p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("Set %s", parts[1]))
return true return true
} }
if parts[0] == "get" && len(parts) == 2 && forbiddenKeys[parts[1]] { if parts[0] == "get" && len(parts) == 2 && forbiddenKeys[parts[1]] {
p.Bot.SendMessage(message.Channel, "You cannot access that key") p.Bot.Send(bot.Message, message.Channel, "You cannot access that key")
return true return true
} else if parts[0] == "get" && len(parts) == 2 { } else if parts[0] == "get" && len(parts) == 2 {
v := p.cfg.Get(parts[1], "<unknown>") v := p.cfg.Get(parts[1], "<unknown>")
p.Bot.SendMessage(message.Channel, fmt.Sprintf("%s: %s", parts[1], v)) p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("%s: %s", parts[1], v))
return true return true
} }
@ -102,10 +104,10 @@ func (p *AdminPlugin) handleVariables(message msg.Message) bool {
_, err := p.db.Exec(`delete from variables where name=? and value=?`, variable, value) _, err := p.db.Exec(`delete from variables where name=? and value=?`, variable, value)
if err != nil { if err != nil {
p.Bot.SendMessage(message.Channel, "I'm broke and need attention in my variable creation code.") p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
log.Println("[admin]: ", err) log.Println("[admin]: ", err)
} else { } else {
p.Bot.SendMessage(message.Channel, "Removed.") p.Bot.Send(bot.Message, message.Channel, "Removed.")
} }
return true return true
@ -123,43 +125,32 @@ func (p *AdminPlugin) handleVariables(message msg.Message) bool {
row := p.db.QueryRow(`select count(*) from variables where value = ?`, variable, value) row := p.db.QueryRow(`select count(*) from variables where value = ?`, variable, value)
err := row.Scan(&count) err := row.Scan(&count)
if err != nil { if err != nil {
p.Bot.SendMessage(message.Channel, "I'm broke and need attention in my variable creation code.") p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
log.Println("[admin]: ", err) log.Println("[admin]: ", err)
return true return true
} }
if count > 0 { if count > 0 {
p.Bot.SendMessage(message.Channel, "I've already got that one.") p.Bot.Send(bot.Message, message.Channel, "I've already got that one.")
} else { } else {
_, err := p.db.Exec(`INSERT INTO variables (name, value) VALUES (?, ?)`, variable, value) _, err := p.db.Exec(`INSERT INTO variables (name, value) VALUES (?, ?)`, variable, value)
if err != nil { if err != nil {
p.Bot.SendMessage(message.Channel, "I'm broke and need attention in my variable creation code.") p.Bot.Send(bot.Message, message.Channel, "I'm broke and need attention in my variable creation code.")
log.Println("[admin]: ", err) log.Println("[admin]: ", err)
return true return true
} }
p.Bot.SendMessage(message.Channel, "Added.") p.Bot.Send(bot.Message, message.Channel, "Added.")
} }
return true return true
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *AdminPlugin) Help(channel string, parts []string) { func (p *AdminPlugin) help(kind bot.Kind, m msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "This does super secret things that you're not allowed to know about.") p.Bot.Send(bot.Message, m.Channel, "This does super secret things that you're not allowed to know about.")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *AdminPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *AdminPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *AdminPlugin) RegisterWeb() *string { func (p *AdminPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *AdminPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -22,12 +22,12 @@ func setup(t *testing.T) (*AdminPlugin, *bot.MockBot) {
return a, mb return a, mb
} }
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -38,7 +38,7 @@ func makeMessage(payload string) msg.Message {
func TestSet(t *testing.T) { func TestSet(t *testing.T) {
a, mb := setup(t) a, mb := setup(t)
expected := "test value" expected := "test value"
a.Message(makeMessage("!set test.key " + expected)) a.message(makeMessage("!set test.key " + expected))
actual := mb.Config().Get("test.key", "ERR") actual := mb.Config().Get("test.key", "ERR")
assert.Equal(t, expected, actual) assert.Equal(t, expected, actual)
} }
@ -47,7 +47,7 @@ func TestGetValue(t *testing.T) {
a, mb := setup(t) a, mb := setup(t)
expected := "value" expected := "value"
mb.Config().Set("test.key", "value") mb.Config().Set("test.key", "value")
a.Message(makeMessage("!get test.key")) a.message(makeMessage("!get test.key"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], expected) assert.Contains(t, mb.Messages[0], expected)
} }
@ -55,7 +55,7 @@ func TestGetValue(t *testing.T) {
func TestGetEmpty(t *testing.T) { func TestGetEmpty(t *testing.T) {
a, mb := setup(t) a, mb := setup(t)
expected := "test.key: <unknown>" expected := "test.key: <unknown>"
a.Message(makeMessage("!get test.key")) a.message(makeMessage("!get test.key"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, expected, mb.Messages[0]) assert.Equal(t, expected, mb.Messages[0])
} }
@ -63,7 +63,7 @@ func TestGetEmpty(t *testing.T) {
func TestGetForbidden(t *testing.T) { func TestGetForbidden(t *testing.T) {
a, mb := setup(t) a, mb := setup(t)
expected := "cannot access" expected := "cannot access"
a.Message(makeMessage("!get slack.token")) a.message(makeMessage("!get slack.token"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], expected) assert.Contains(t, mb.Messages[0], expected)
} }

View File

@ -52,24 +52,24 @@ type BabblerArc struct {
Frequency int64 `db:"frequency"` Frequency int64 `db:"frequency"`
} }
func New(bot bot.Bot) *BabblerPlugin { func New(b bot.Bot) *BabblerPlugin {
log.SetFlags(log.LstdFlags | log.Lshortfile) log.SetFlags(log.LstdFlags | log.Lshortfile)
if _, err := bot.DB().Exec(`create table if not exists babblers ( if _, err := b.DB().Exec(`create table if not exists babblers (
id integer primary key, id integer primary key,
babbler string babbler string
);`); err != nil { );`); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if _, err := bot.DB().Exec(`create table if not exists babblerWords ( if _, err := b.DB().Exec(`create table if not exists babblerWords (
id integer primary key, id integer primary key,
word string word string
);`); err != nil { );`); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if _, err := bot.DB().Exec(`create table if not exists babblerNodes ( if _, err := b.DB().Exec(`create table if not exists babblerNodes (
id integer primary key, id integer primary key,
babblerId integer, babblerId integer,
wordId integer, wordId integer,
@ -79,7 +79,7 @@ func New(bot bot.Bot) *BabblerPlugin {
log.Fatal(err) log.Fatal(err)
} }
if _, err := bot.DB().Exec(`create table if not exists babblerArcs ( if _, err := b.DB().Exec(`create table if not exists babblerArcs (
id integer primary key, id integer primary key,
fromNodeId integer, fromNodeId integer,
toNodeId interger, toNodeId interger,
@ -89,17 +89,20 @@ func New(bot bot.Bot) *BabblerPlugin {
} }
plugin := &BabblerPlugin{ plugin := &BabblerPlugin{
Bot: bot, Bot: b,
db: bot.DB(), db: b.DB(),
WithGoRoutines: true, WithGoRoutines: true,
} }
plugin.createNewWord("") plugin.createNewWord("")
b.Register(plugin, bot.Message, plugin.message)
b.Register(plugin, bot.Help, plugin.help)
return plugin return plugin
} }
func (p *BabblerPlugin) Message(message msg.Message) bool { func (p *BabblerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
lowercase := strings.ToLower(message.Body) lowercase := strings.ToLower(message.Body)
tokens := strings.Fields(lowercase) tokens := strings.Fields(lowercase)
numTokens := len(tokens) numTokens := len(tokens)
@ -141,12 +144,12 @@ func (p *BabblerPlugin) Message(message msg.Message) bool {
} }
if saidSomething { if saidSomething {
p.Bot.SendMessage(message.Channel, saidWhat) p.Bot.Send(bot.Message, message.Channel, saidWhat)
} }
return saidSomething return saidSomething
} }
func (p *BabblerPlugin) Help(channel string, parts []string) { func (p *BabblerPlugin) help(kind bot.Kind, msg msg.Message, args ...interface{}) bool {
commands := []string{ commands := []string{
"initialize babbler for seabass", "initialize babbler for seabass",
"merge babbler drseabass into seabass", "merge babbler drseabass into seabass",
@ -155,15 +158,8 @@ func (p *BabblerPlugin) Help(channel string, parts []string) {
"seabass says-middle-out ...", "seabass says-middle-out ...",
"seabass says-bridge ... | ...", "seabass says-bridge ... | ...",
} }
p.Bot.SendMessage(channel, strings.Join(commands, "\n\n")) p.Bot.Send(bot.Message, msg.Channel, strings.Join(commands, "\n\n"))
} return true
func (p *BabblerPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *BabblerPlugin) BotMessage(message msg.Message) bool {
return false
} }
func (p *BabblerPlugin) RegisterWeb() *string { func (p *BabblerPlugin) RegisterWeb() *string {
@ -934,5 +930,3 @@ func (p *BabblerPlugin) babbleSeedBookends(babblerName string, start, end []stri
return strings.Join(words, " "), nil return strings.Join(words, " "), nil
} }
func (p *BabblerPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -41,7 +41,7 @@ func TestBabblerNoBabbler(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
bp.Message(makeMessage("!seabass2 says")) bp.message(makeMessage("!seabass2 says"))
res := assert.Len(t, mb.Messages, 0) res := assert.Len(t, mb.Messages, 0)
assert.True(t, res) assert.True(t, res)
// assert.Contains(t, mb.Messages[0], "seabass2 babbler not found") // assert.Contains(t, mb.Messages[0], "seabass2 babbler not found")
@ -51,9 +51,9 @@ func TestBabblerNothingSaid(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
res := bp.Message(makeMessage("initialize babbler for seabass")) res := bp.message(makeMessage("initialize babbler for seabass"))
assert.True(t, res) assert.True(t, res)
res = bp.Message(makeMessage("!seabass says")) res = bp.message(makeMessage("!seabass says"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
assert.Contains(t, mb.Messages[0], "okay.") assert.Contains(t, mb.Messages[0], "okay.")
@ -64,14 +64,14 @@ func TestBabbler(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is a message") k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
seabass.Body = "This is another message" seabass.Body = "This is another message"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "This is a long message" seabass.Body = "This is a long message"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says")) res = bp.message(makeMessage("!seabass says"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "this is") assert.Contains(t, mb.Messages[0], "this is")
@ -82,14 +82,14 @@ func TestBabblerSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is a message") k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
seabass.Body = "This is another message" seabass.Body = "This is another message"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "This is a long message" seabass.Body = "This is a long message"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says long")) res = bp.message(makeMessage("!seabass says long"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "long message") assert.Contains(t, mb.Messages[0], "long message")
@ -99,14 +99,14 @@ func TestBabblerMultiSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is a message") k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
seabass.Body = "This is another message" seabass.Body = "This is another message"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "This is a long message" seabass.Body = "This is a long message"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says This is a long")) res = bp.message(makeMessage("!seabass says This is a long"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "this is a long message") assert.Contains(t, mb.Messages[0], "this is a long message")
@ -116,14 +116,14 @@ func TestBabblerMultiSeed2(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is a message") k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
seabass.Body = "This is another message" seabass.Body = "This is another message"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "This is a long message" seabass.Body = "This is a long message"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says is a long")) res = bp.message(makeMessage("!seabass says is a long"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "is a long message") assert.Contains(t, mb.Messages[0], "is a long message")
@ -133,14 +133,14 @@ func TestBabblerBadSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is a message") k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
bp.Message(seabass) bp.message(k, seabass)
seabass.Body = "This is another message" seabass.Body = "This is another message"
bp.Message(seabass) bp.message(k, seabass)
seabass.Body = "This is a long message" seabass.Body = "This is a long message"
bp.Message(seabass) bp.message(k, seabass)
bp.Message(makeMessage("!seabass says noooo this is bad")) bp.message(makeMessage("!seabass says noooo this is bad"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "seabass never said 'noooo this is bad'") assert.Contains(t, mb.Messages[0], "seabass never said 'noooo this is bad'")
} }
@ -149,14 +149,14 @@ func TestBabblerBadSeed2(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is a message") k, seabass := makeMessage("This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
bp.Message(seabass) bp.message(k, seabass)
seabass.Body = "This is another message" seabass.Body = "This is another message"
bp.Message(seabass) bp.message(k, seabass)
seabass.Body = "This is a long message" seabass.Body = "This is a long message"
bp.Message(seabass) bp.message(k, seabass)
bp.Message(makeMessage("!seabass says This is a really")) bp.message(makeMessage("!seabass says This is a really"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "seabass never said 'this is a really'") assert.Contains(t, mb.Messages[0], "seabass never said 'this is a really'")
} }
@ -165,15 +165,15 @@ func TestBabblerSuffixSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is message one") k, seabass := makeMessage("This is message one")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
seabass.Body = "It's easier to test with unique messages" seabass.Body = "It's easier to test with unique messages"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "hi there" seabass.Body = "hi there"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-tail message one")) res = bp.message(makeMessage("!seabass says-tail message one"))
res = bp.Message(makeMessage("!seabass says-tail with unique")) res = bp.message(makeMessage("!seabass says-tail with unique"))
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "this is message one") assert.Contains(t, mb.Messages[0], "this is message one")
@ -184,14 +184,14 @@ func TestBabblerBadSuffixSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("This is message one") k, seabass := makeMessage("This is message one")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
seabass.Body = "It's easier to test with unique messages" seabass.Body = "It's easier to test with unique messages"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "hi there" seabass.Body = "hi there"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-tail anything true")) res = bp.message(makeMessage("!seabass says-tail anything true"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "seabass never said 'anything true'") assert.Contains(t, mb.Messages[0], "seabass never said 'anything true'")
@ -201,10 +201,10 @@ func TestBabblerBookendSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("It's easier to test with unique messages") k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-bridge It's easier | unique messages")) res = bp.message(makeMessage("!seabass says-bridge It's easier | unique messages"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "it's easier to test with unique messages") assert.Contains(t, mb.Messages[0], "it's easier to test with unique messages")
@ -214,10 +214,10 @@ func TestBabblerBookendSeedShort(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("It's easier to test with unique messages") k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-bridge It's easier to test with | unique messages")) res = bp.message(makeMessage("!seabass says-bridge It's easier to test with | unique messages"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "it's easier to test with unique messages") assert.Contains(t, mb.Messages[0], "it's easier to test with unique messages")
@ -227,10 +227,10 @@ func TestBabblerBadBookendSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("It's easier to test with unique messages") k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-bridge It's easier | not unique messages")) res = bp.message(makeMessage("!seabass says-bridge It's easier | not unique messages"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "seabass never said 'it's easier ... not unique messages'") assert.Contains(t, mb.Messages[0], "seabass never said 'it's easier ... not unique messages'")
@ -240,10 +240,10 @@ func TestBabblerMiddleOutSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("It's easier to test with unique messages") k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-middle-out test with")) res = bp.message(makeMessage("!seabass says-middle-out test with"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "it's easier to test with unique messages") assert.Contains(t, mb.Messages[0], "it's easier to test with unique messages")
@ -253,10 +253,10 @@ func TestBabblerBadMiddleOutSeed(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("It's easier to test with unique messages") k, seabass := makeMessage("It's easier to test with unique messages")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
res = bp.Message(makeMessage("!seabass says-middle-out anything true")) res = bp.message(makeMessage("!seabass says-middle-out anything true"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Equal(t, mb.Messages[0], "seabass never said 'anything true'") assert.Equal(t, mb.Messages[0], "seabass never said 'anything true'")
@ -266,10 +266,10 @@ func TestBabblerBatch(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
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?") 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(seabass) res := bp.message(k, seabass)
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
res = bp.Message(makeMessage("!seabass says")) res = bp.message(makeMessage("!seabass says"))
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[1], "this is") assert.Contains(t, mb.Messages[1], "this is")
@ -281,23 +281,23 @@ func TestBabblerMerge(t *testing.T) {
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
seabass := makeMessage("<seabass> This is a message") k, seabass := makeMessage("<seabass> This is a message")
seabass.User = &user.User{Name: "seabass"} seabass.User = &user.User{Name: "seabass"}
res := bp.Message(seabass) res := bp.message(k, seabass)
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
seabass.Body = "<seabass> This is another message" seabass.Body = "<seabass> This is another message"
res = bp.Message(seabass) res = bp.message(k, seabass)
seabass.Body = "<seabass> This is a long message" seabass.Body = "<seabass> This is a long message"
res = bp.Message(seabass) res = bp.message(k, seabass)
res = bp.Message(makeMessage("!merge babbler seabass into seabass2")) res = bp.message(makeMessage("!merge babbler seabass into seabass2"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "mooooiggged") assert.Contains(t, mb.Messages[0], "mooooiggged")
res = bp.Message(makeMessage("!seabass2 says")) res = bp.message(makeMessage("!seabass2 says"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
@ -309,24 +309,10 @@ func TestHelp(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)
assert.NotNil(t, bp) assert.NotNil(t, bp)
bp.Help("channel", []string{}) bp.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBotMessage(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
assert.False(t, bp.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
mb := bot.NewMockBot()
bp := newBabblerPlugin(mb)
assert.NotNil(t, bp)
assert.False(t, bp.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
bp := newBabblerPlugin(mb) bp := newBabblerPlugin(mb)

View File

@ -38,8 +38,8 @@ type untappdUser struct {
} }
// New BeersPlugin creates a new BeersPlugin with the Plugin interface // New BeersPlugin creates a new BeersPlugin with the Plugin interface
func New(bot bot.Bot) *BeersPlugin { func New(b bot.Bot) *BeersPlugin {
if _, err := bot.DB().Exec(`create table if not exists untappd ( if _, err := b.DB().Exec(`create table if not exists untappd (
id integer primary key, id integer primary key,
untappdUser string, untappdUser string,
channel string, channel string,
@ -49,19 +49,21 @@ func New(bot bot.Bot) *BeersPlugin {
log.Fatal(err) log.Fatal(err)
} }
p := BeersPlugin{ p := BeersPlugin{
Bot: bot, Bot: b,
db: bot.DB(), db: b.DB(),
} }
for _, channel := range bot.Config().GetArray("Untappd.Channels", []string{}) { for _, channel := range b.Config().GetArray("Untappd.Channels", []string{}) {
go p.untappdLoop(channel) go p.untappdLoop(channel)
} }
b.Register(p, bot.Message, p.message)
b.Register(p, bot.Help, p.help)
return &p return &p
} }
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *BeersPlugin) Message(message msg.Message) bool { func (p *BeersPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
parts := strings.Fields(message.Body) parts := strings.Fields(message.Body)
if len(parts) == 0 { if len(parts) == 0 {
@ -81,13 +83,13 @@ func (p *BeersPlugin) Message(message msg.Message) bool {
count, err := strconv.Atoi(parts[2]) count, err := strconv.Atoi(parts[2])
if err != nil { if err != nil {
// if it's not a number, maybe it's a nick! // if it's not a number, maybe it's a nick!
p.Bot.SendMessage(channel, "Sorry, that didn't make any sense.") p.Bot.Send(bot.Message, channel, "Sorry, that didn't make any sense.")
} }
if count < 0 { if count < 0 {
// you can't be negative // you can't be negative
msg := fmt.Sprintf("Sorry %s, you can't have negative beers!", nick) msg := fmt.Sprintf("Sorry %s, you can't have negative beers!", nick)
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, channel, msg)
return true return true
} }
if parts[1] == "+=" { if parts[1] == "+=" {
@ -101,14 +103,14 @@ func (p *BeersPlugin) Message(message msg.Message) bool {
p.randomReply(channel) p.randomReply(channel)
} }
} else { } else {
p.Bot.SendMessage(channel, "I don't know your math.") p.Bot.Send(bot.Message, channel, "I don't know your math.")
} }
} else if len(parts) == 2 { } else if len(parts) == 2 {
if p.doIKnow(parts[1]) { if p.doIKnow(parts[1]) {
p.reportCount(parts[1], channel, false) p.reportCount(parts[1], channel, false)
} else { } else {
msg := fmt.Sprintf("Sorry, I don't know %s.", parts[1]) msg := fmt.Sprintf("Sorry, I don't know %s.", parts[1])
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, channel, msg)
} }
} else if len(parts) == 1 { } else if len(parts) == 1 {
p.reportCount(nick, channel, true) p.reportCount(nick, channel, true)
@ -132,7 +134,7 @@ func (p *BeersPlugin) Message(message msg.Message) bool {
channel := message.Channel channel := message.Channel
if len(parts) < 2 { if len(parts) < 2 {
p.Bot.SendMessage(channel, "You must also provide a user name.") p.Bot.Send(bot.Message, channel, "You must also provide a user name.")
} else if len(parts) == 3 { } else if len(parts) == 3 {
chanNick = parts[2] chanNick = parts[2]
} else if len(parts) == 4 { } else if len(parts) == 4 {
@ -154,7 +156,7 @@ func (p *BeersPlugin) Message(message msg.Message) bool {
log.Println("Error registering untappd: ", err) log.Println("Error registering untappd: ", err)
} }
if count > 0 { if count > 0 {
p.Bot.SendMessage(channel, "I'm already watching you.") p.Bot.Send(bot.Message, channel, "I'm already watching you.")
return true return true
} }
_, err = p.db.Exec(`insert into untappd ( _, err = p.db.Exec(`insert into untappd (
@ -170,11 +172,11 @@ func (p *BeersPlugin) Message(message msg.Message) bool {
) )
if err != nil { if err != nil {
log.Println("Error registering untappd: ", err) log.Println("Error registering untappd: ", err)
p.Bot.SendMessage(channel, "I can't see.") p.Bot.Send(bot.Message, channel, "I can't see.")
return true return true
} }
p.Bot.SendMessage(channel, "I'll be watching you.") p.Bot.Send(bot.Message, channel, "I'll be watching you.")
p.checkUntappd(channel) p.checkUntappd(channel)
@ -190,17 +192,13 @@ func (p *BeersPlugin) Message(message msg.Message) bool {
return false return false
} }
// Empty event handler because this plugin does not do anything on event recv
func (p *BeersPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *BeersPlugin) Help(channel string, parts []string) { func (p *BeersPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
msg := "Beers: imbibe by using either beers +=,=,++ or with the !imbibe/drink " + 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 " + "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!" "to reset, just !puke it all up!"
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
return true
} }
func getUserBeers(db *sqlx.DB, user string) counter.Item { func getUserBeers(db *sqlx.DB, user string) counter.Item {
@ -239,13 +237,13 @@ func (p *BeersPlugin) reportCount(nick, channel string, himself bool) {
msg = fmt.Sprintf("You've had %d beers so far, %s.", beers, nick) msg = fmt.Sprintf("You've had %d beers so far, %s.", beers, nick)
} }
} }
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, channel, msg)
} }
func (p *BeersPlugin) puke(user string, channel string) { func (p *BeersPlugin) puke(user string, channel string) {
p.setBeers(user, 0) p.setBeers(user, 0)
msg := fmt.Sprintf("Ohhhhhh, and a reversal of fortune for %s!", user) msg := fmt.Sprintf("Ohhhhhh, and a reversal of fortune for %s!", user)
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, channel, msg)
} }
func (p *BeersPlugin) doIKnow(nick string) bool { func (p *BeersPlugin) doIKnow(nick string) bool {
@ -260,7 +258,7 @@ func (p *BeersPlugin) doIKnow(nick string) bool {
// Sends random affirmation to the channel. This could be better (with a datastore for sayings) // 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(channel string) {
replies := []string{"ZIGGY! ZAGGY!", "HIC!", "Stay thirsty, my friend!"} replies := []string{"ZIGGY! ZAGGY!", "HIC!", "Stay thirsty, my friend!"}
p.Bot.SendMessage(channel, replies[rand.Intn(len(replies))]) p.Bot.Send(bot.Message, channel, replies[rand.Intn(len(replies))])
} }
type checkin struct { type checkin struct {
@ -421,7 +419,7 @@ func (p *BeersPlugin) checkUntappd(channel string) {
} }
log.Println("checkin id:", checkin.Checkin_id, "Message:", msg) log.Println("checkin id:", checkin.Checkin_id, "Message:", msg)
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, channel, msg)
} }
} }
@ -439,14 +437,7 @@ func (p *BeersPlugin) untappdLoop(channel string) {
} }
} }
// Handler for bot's own messages
func (p *BeersPlugin) BotMessage(message msg.Message) bool {
return false
}
// Register any web URLs desired // Register any web URLs desired
func (p *BeersPlugin) RegisterWeb() *string { func (p BeersPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *BeersPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -13,12 +13,12 @@ import (
"github.com/velour/catbase/plugins/counter" "github.com/velour/catbase/plugins/counter"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -31,8 +31,8 @@ func makeBeersPlugin(t *testing.T) (*BeersPlugin, *bot.MockBot) {
counter.New(mb) counter.New(mb)
mb.DB().MustExec(`delete from counter; delete from counter_alias;`) mb.DB().MustExec(`delete from counter; delete from counter_alias;`)
b := New(mb) b := New(mb)
b.Message(makeMessage("!mkalias beer :beer:")) b.message(makeMessage("!mkalias beer :beer:"))
b.Message(makeMessage("!mkalias beers :beer:")) b.message(makeMessage("!mkalias beers :beer:"))
return b, mb return b, mb
} }
@ -49,9 +49,9 @@ func TestCounter(t *testing.T) {
func TestImbibe(t *testing.T) { func TestImbibe(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("!imbibe")) b.message(makeMessage("!imbibe"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
b.Message(makeMessage("!imbibe")) b.message(makeMessage("!imbibe"))
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
@ -59,7 +59,7 @@ func TestImbibe(t *testing.T) {
} }
func TestEq(t *testing.T) { func TestEq(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("!beers = 3")) b.message(makeMessage("!beers = 3"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
@ -68,7 +68,7 @@ func TestEq(t *testing.T) {
func TestEqNeg(t *testing.T) { func TestEqNeg(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("!beers = -3")) b.message(makeMessage("!beers = -3"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
@ -77,8 +77,8 @@ func TestEqNeg(t *testing.T) {
func TestEqZero(t *testing.T) { func TestEqZero(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("beers += 5")) b.message(makeMessage("beers += 5"))
b.Message(makeMessage("!beers = 0")) b.message(makeMessage("!beers = 0"))
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
assert.Contains(t, mb.Messages[1], "reversal of fortune") assert.Contains(t, mb.Messages[1], "reversal of fortune")
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
@ -88,9 +88,9 @@ func TestEqZero(t *testing.T) {
func TestBeersPlusEq(t *testing.T) { func TestBeersPlusEq(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("beers += 5")) b.message(makeMessage("beers += 5"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
b.Message(makeMessage("beers += 5")) b.message(makeMessage("beers += 5"))
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
@ -99,11 +99,11 @@ func TestBeersPlusEq(t *testing.T) {
func TestPuke(t *testing.T) { func TestPuke(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("beers += 5")) b.message(makeMessage("beers += 5"))
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 5, it.Count) assert.Equal(t, 5, it.Count)
b.Message(makeMessage("puke")) b.message(makeMessage("puke"))
it, err = counter.GetItem(mb.DB(), "tester", itemName) it, err = counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, it.Count) assert.Equal(t, 0, it.Count)
@ -111,30 +111,20 @@ func TestPuke(t *testing.T) {
func TestBeersReport(t *testing.T) { func TestBeersReport(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Message(makeMessage("beers += 5")) b.message(makeMessage("beers += 5"))
it, err := counter.GetItem(mb.DB(), "tester", itemName) it, err := counter.GetItem(mb.DB(), "tester", itemName)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 5, it.Count) assert.Equal(t, 5, it.Count)
b.Message(makeMessage("beers")) b.message(makeMessage("beers"))
assert.Contains(t, mb.Messages[1], "5 beers") assert.Contains(t, mb.Messages[1], "5 beers")
} }
func TestHelp(t *testing.T) { func TestHelp(t *testing.T) {
b, mb := makeBeersPlugin(t) b, mb := makeBeersPlugin(t)
b.Help("channel", []string{}) b.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBotMessage(t *testing.T) {
b, _ := makeBeersPlugin(t)
assert.False(t, b.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
b, _ := makeBeersPlugin(t)
assert.False(t, b.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
b, _ := makeBeersPlugin(t) b, _ := makeBeersPlugin(t)
assert.Nil(t, b.RegisterWeb()) assert.Nil(t, b.RegisterWeb())

View File

@ -17,13 +17,15 @@ type CSWPlugin struct {
Config *config.Config Config *config.Config
} }
func New(bot bot.Bot) *CSWPlugin { func New(b bot.Bot) *CSWPlugin {
return &CSWPlugin{ csw := &CSWPlugin{
Bot: bot, Bot: b,
} }
b.Register(csw, bot.Message, csw.message)
return csw
} }
func (p *CSWPlugin) Message(message msg.Message) bool { func (p *CSWPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !message.Command { if !message.Command {
return false return false
} }
@ -63,25 +65,13 @@ func (p *CSWPlugin) Message(message msg.Message) bool {
} }
} }
p.Bot.SendMessage(message.Channel, responses[rand.Intn(len(responses))]) p.Bot.Send(bot.Message, message.Channel, responses[rand.Intn(len(responses))])
return true return true
} }
return false return false
} }
func (p *CSWPlugin) Help(channel string, parts []string) {}
func (p *CSWPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *CSWPlugin) BotMessage(message msg.Message) bool {
return false
}
func (p *CSWPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }
func (p *CSWPlugin) RegisterWeb() *string { func (p *CSWPlugin) RegisterWeb() *string {
return nil return nil
} }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -29,7 +29,7 @@ func Test0(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!should I drink a beer?")) res := c.message(makeMessage("!should I drink a beer?"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
possibilities := []string{"Yes.", "No.", "Maybe.", "For fucks sake, how should I know?"} possibilities := []string{"Yes.", "No.", "Maybe.", "For fucks sake, how should I know?"}
@ -47,7 +47,7 @@ func Test1(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!should I drink a beer or a bourbon?")) res := c.message(makeMessage("!should I drink a beer or a bourbon?"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
possibilities := []string{"The former.", "The latter.", "Obviously the former.", "Clearly the latter.", "Can't it be both?"} possibilities := []string{"The former.", "The latter.", "Obviously the former.", "Clearly the latter.", "Can't it be both?"}
@ -65,7 +65,7 @@ func Test2(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!could I drink a beer or a bourbon?")) res := c.message(makeMessage("!could I drink a beer or a bourbon?"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
possibilities := []string{"Yes.", "No.", "Maybe.", "For fucks sake, how should I know?"} possibilities := []string{"Yes.", "No.", "Maybe.", "For fucks sake, how should I know?"}
@ -83,7 +83,7 @@ func Test3(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!would I die if I drank too much bourbon?")) res := c.message(makeMessage("!would I die if I drank too much bourbon?"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
possibilities := []string{"Yes.", "No.", "Maybe.", "For fucks sake, how should I know?"} possibilities := []string{"Yes.", "No.", "Maybe.", "For fucks sake, how should I know?"}
@ -101,7 +101,7 @@ func Test4(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!would I die or be sick if I drank all the bourbon?")) res := c.message(makeMessage("!would I die or be sick if I drank all the bourbon?"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
possibilities := []string{"The former.", "The latter.", "Obviously the former.", "Clearly the latter.", "Can't it be both?"} possibilities := []string{"The former.", "The latter.", "Obviously the former.", "Clearly the latter.", "Can't it be both?"}
@ -119,7 +119,7 @@ func Test5(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!should I have another beer or bourbon or tequila?")) res := c.message(makeMessage("!should I have another beer or bourbon or tequila?"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
possibilities := []string{"I'd say option", "You'd be an idiot not to choose the"} possibilities := []string{"I'd say option", "You'd be an idiot not to choose the"}

View File

@ -172,31 +172,34 @@ func (i *Item) Delete() error {
} }
// NewCounterPlugin creates a new CounterPlugin with the Plugin interface // NewCounterPlugin creates a new CounterPlugin with the Plugin interface
func New(bot bot.Bot) *CounterPlugin { func New(b bot.Bot) *CounterPlugin {
tx := bot.DB().MustBegin() tx := b.DB().MustBegin()
bot.DB().MustExec(`create table if not exists counter ( b.DB().MustExec(`create table if not exists counter (
id integer primary key, id integer primary key,
nick string, nick string,
item string, item string,
count integer count integer
);`) );`)
bot.DB().MustExec(`create table if not exists counter_alias ( b.DB().MustExec(`create table if not exists counter_alias (
id integer PRIMARY KEY AUTOINCREMENT, id integer PRIMARY KEY AUTOINCREMENT,
item string NOT NULL UNIQUE, item string NOT NULL UNIQUE,
points_to string NOT NULL points_to string NOT NULL
);`) );`)
tx.Commit() tx.Commit()
return &CounterPlugin{ cp := &CounterPlugin{
Bot: bot, Bot: b,
DB: bot.DB(), DB: b.DB(),
} }
b.Register(cp, bot.Message, cp.message)
b.Register(cp, bot.Help, cp.help)
return cp
} }
// Message responds to the bot hook on recieving messages. // Message responds to the bot hook on recieving messages.
// This function returns true if the plugin responds in a meaningful way to the // 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 // users message. Otherwise, the function returns false and the bot continues
// execution of other plugins. // execution of other plugins.
func (p *CounterPlugin) Message(message msg.Message) bool { func (p *CounterPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
// This bot does not reply to anything // This bot does not reply to anything
nick := message.User.Name nick := message.User.Name
channel := message.Channel channel := message.Channel
@ -211,7 +214,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
log.Println(err) log.Println(err)
return false return false
} }
p.Bot.SendMessage(channel, fmt.Sprintf("Created alias %s -> %s", p.Bot.Send(bot.Message, channel, fmt.Sprintf("Created alias %s -> %s",
parts[1], parts[2])) parts[1], parts[2]))
return true return true
} else if strings.ToLower(parts[0]) == "leaderboard" { } else if strings.ToLower(parts[0]) == "leaderboard" {
@ -241,7 +244,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
it.Item, it.Item,
) )
} }
p.Bot.SendMessage(channel, out) p.Bot.Send(bot.Message, channel, out)
return true return true
} else if match := teaMatcher.MatchString(message.Body); match { } else if match := teaMatcher.MatchString(message.Body); match {
// check for tea match TTT // check for tea match TTT
@ -250,14 +253,14 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
items, err := GetItems(p.DB, strings.ToLower(nick)) items, err := GetItems(p.DB, strings.ToLower(nick))
if err != nil { if err != nil {
log.Printf("Error getting items to reset %s: %s", nick, err) log.Printf("Error getting items to reset %s: %s", nick, err)
p.Bot.SendMessage(channel, "Something is technically wrong with your counters.") p.Bot.Send(bot.Message, channel, "Something is technically wrong with your counters.")
return true return true
} }
log.Printf("Items: %+v", items) log.Printf("Items: %+v", items)
for _, item := range items { for _, item := range items {
item.Delete() item.Delete()
} }
p.Bot.SendMessage(channel, fmt.Sprintf("%s, you are as new, my son.", nick)) p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s, you are as new, my son.", nick))
return true return true
} else if message.Command && parts[0] == "inspect" && len(parts) == 2 { } else if message.Command && parts[0] == "inspect" && len(parts) == 2 {
var subject string var subject string
@ -273,7 +276,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
items, err := GetItems(p.DB, subject) items, err := GetItems(p.DB, subject)
if err != nil { if err != nil {
log.Fatalf("Error retrieving items for %s: %s", subject, err) log.Fatalf("Error retrieving items for %s: %s", subject, err)
p.Bot.SendMessage(channel, "Something went wrong finding that counter;") p.Bot.Send(bot.Message, channel, "Something went wrong finding that counter;")
return true return true
} }
@ -293,11 +296,11 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
resp += "." resp += "."
if count == 0 { if count == 0 {
p.Bot.SendMessage(channel, fmt.Sprintf("%s has no counters.", subject)) p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has no counters.", subject))
return true return true
} }
p.Bot.SendMessage(channel, resp) p.Bot.Send(bot.Message, channel, resp)
return true return true
} else if message.Command && len(parts) == 2 && parts[0] == "clear" { } else if message.Command && len(parts) == 2 && parts[0] == "clear" {
subject := strings.ToLower(nick) subject := strings.ToLower(nick)
@ -306,17 +309,17 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
it, err := GetItem(p.DB, subject, itemName) it, err := GetItem(p.DB, subject, itemName)
if err != nil { if err != nil {
log.Printf("Error getting item to remove %s.%s: %s", subject, itemName, err) log.Printf("Error getting item to remove %s.%s: %s", subject, itemName, err)
p.Bot.SendMessage(channel, "Something went wrong removing that counter;") p.Bot.Send(bot.Message, channel, "Something went wrong removing that counter;")
return true return true
} }
err = it.Delete() err = it.Delete()
if err != nil { if err != nil {
log.Printf("Error removing item %s.%s: %s", subject, itemName, err) log.Printf("Error removing item %s.%s: %s", subject, itemName, err)
p.Bot.SendMessage(channel, "Something went wrong removing that counter;") p.Bot.Send(bot.Message, channel, "Something went wrong removing that counter;")
return true return true
} }
p.Bot.SendAction(channel, fmt.Sprintf("chops a few %s out of his brain", p.Bot.Send(bot.Action, channel, fmt.Sprintf("chops a few %s out of his brain",
itemName)) itemName))
return true return true
@ -339,7 +342,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
item, err := GetItem(p.DB, subject, itemName) item, err := GetItem(p.DB, subject, itemName)
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
p.Bot.SendMessage(channel, fmt.Sprintf("I don't think %s has any %s.", p.Bot.Send(bot.Message, channel, fmt.Sprintf("I don't think %s has any %s.",
subject, itemName)) subject, itemName))
return true return true
case err != nil: case err != nil:
@ -348,7 +351,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
return true return true
} }
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, item.Count, p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject, item.Count,
itemName)) itemName))
return true return true
@ -379,7 +382,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
} }
log.Printf("About to update item: %#v", item) log.Printf("About to update item: %#v", item)
item.UpdateDelta(1) item.UpdateDelta(1)
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} else if strings.HasSuffix(parts[0], "--") { } else if strings.HasSuffix(parts[0], "--") {
@ -391,7 +394,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
return false return false
} }
item.UpdateDelta(-1) item.UpdateDelta(-1)
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} }
@ -420,7 +423,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
n, _ := strconv.Atoi(parts[2]) n, _ := strconv.Atoi(parts[2])
log.Printf("About to update item by %d: %#v", n, item) log.Printf("About to update item by %d: %#v", n, item)
item.UpdateDelta(n) item.UpdateDelta(n)
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} else if parts[1] == "-=" { } else if parts[1] == "-=" {
@ -434,7 +437,7 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
n, _ := strconv.Atoi(parts[2]) n, _ := strconv.Atoi(parts[2])
log.Printf("About to update item by -%d: %#v", n, item) log.Printf("About to update item by -%d: %#v", n, item)
item.UpdateDelta(-n) item.UpdateDelta(-n)
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
} }
@ -444,21 +447,12 @@ func (p *CounterPlugin) Message(message msg.Message) bool {
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *CounterPlugin) Help(channel string, parts []string) { func (p *CounterPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "You can set counters incrementally by using "+ p.Bot.Send(bot.Message, message.Channel, "You can set counters incrementally by using "+
"<noun>++ and <noun>--. You can see all of your counters using "+ "<noun>++ and <noun>--. You can see all of your counters using "+
"\"inspect\", erase them with \"clear\", and view single counters with "+ "\"inspect\", erase them with \"clear\", and view single counters with "+
"\"count\".") "\"count\".")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *CounterPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *CounterPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
@ -466,8 +460,6 @@ func (p *CounterPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *CounterPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }
func (p *CounterPlugin) checkMatch(message msg.Message) bool { func (p *CounterPlugin) checkMatch(message msg.Message) bool {
nick := message.User.Name nick := message.User.Name
channel := message.Channel channel := message.Channel
@ -487,7 +479,7 @@ func (p *CounterPlugin) checkMatch(message msg.Message) bool {
} }
log.Printf("About to update item: %#v", item) log.Printf("About to update item: %#v", item)
item.UpdateDelta(1) item.UpdateDelta(1)
p.Bot.SendMessage(channel, fmt.Sprintf("bleep-bloop-blop... %s has %d %s", p.Bot.Send(bot.Message, channel, fmt.Sprintf("bleep-bloop-blop... %s has %d %s",
nick, item.Count, itemName)) nick, item.Count, itemName))
return true return true
} }

View File

@ -22,12 +22,12 @@ func setup(t *testing.T) (*bot.MockBot, *CounterPlugin) {
return mb, c return mb, c
} }
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -38,8 +38,8 @@ func makeMessage(payload string) msg.Message {
func TestThreeSentencesExists(t *testing.T) { func TestThreeSentencesExists(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage(":beer:++")) c.message(makeMessage(":beer:++"))
c.Message(makeMessage(":beer:. Earl Grey. Hot.")) c.message(makeMessage(":beer:. Earl Grey. Hot."))
item, err := GetItem(mb.DB(), "tester", ":beer:") item, err := GetItem(mb.DB(), "tester", ":beer:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, item.Count) assert.Equal(t, 2, item.Count)
@ -49,7 +49,7 @@ func TestThreeSentencesNotExists(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
item, err := GetItem(mb.DB(), "tester", ":beer:") item, err := GetItem(mb.DB(), "tester", ":beer:")
c.Message(makeMessage(":beer:. Earl Grey. Hot.")) c.message(makeMessage(":beer:. Earl Grey. Hot."))
item, err = GetItem(mb.DB(), "tester", ":beer:") item, err = GetItem(mb.DB(), "tester", ":beer:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -58,8 +58,8 @@ func TestThreeSentencesNotExists(t *testing.T) {
func TestTeaEarlGreyHot(t *testing.T) { func TestTeaEarlGreyHot(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("Tea. Earl Grey. Hot.")) c.message(makeMessage("Tea. Earl Grey. Hot."))
c.Message(makeMessage("Tea. Earl Grey. Hot.")) c.message(makeMessage("Tea. Earl Grey. Hot."))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, item.Count) assert.Equal(t, 2, item.Count)
@ -68,8 +68,8 @@ func TestTeaEarlGreyHot(t *testing.T) {
func TestTeaTwoPeriods(t *testing.T) { func TestTeaTwoPeriods(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("Tea. Earl Grey.")) c.message(makeMessage("Tea. Earl Grey."))
c.Message(makeMessage("Tea. Earl Grey.")) c.message(makeMessage("Tea. Earl Grey."))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -78,8 +78,8 @@ func TestTeaTwoPeriods(t *testing.T) {
func TestTeaMultiplePeriods(t *testing.T) { func TestTeaMultiplePeriods(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("Tea. Earl Grey. Spiked. Hot.")) c.message(makeMessage("Tea. Earl Grey. Spiked. Hot."))
c.Message(makeMessage("Tea. Earl Grey. Spiked. Hot.")) c.message(makeMessage("Tea. Earl Grey. Spiked. Hot."))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, item.Count) assert.Equal(t, 2, item.Count)
@ -88,9 +88,9 @@ func TestTeaMultiplePeriods(t *testing.T) {
func TestTeaGreenHot(t *testing.T) { func TestTeaGreenHot(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("Tea. Green. Hot.")) c.message(makeMessage("Tea. Green. Hot."))
c.Message(makeMessage("Tea. Green. Hot")) c.message(makeMessage("Tea. Green. Hot"))
c.Message(makeMessage("Tea. Green. Iced.")) c.message(makeMessage("Tea. Green. Iced."))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, item.Count) assert.Equal(t, 3, item.Count)
@ -99,8 +99,8 @@ func TestTeaGreenHot(t *testing.T) {
func TestTeaUnrelated(t *testing.T) { func TestTeaUnrelated(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("Tea.")) c.message(makeMessage("Tea."))
c.Message(makeMessage("Tea. It's great.")) c.message(makeMessage("Tea. It's great."))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -109,7 +109,7 @@ func TestTeaUnrelated(t *testing.T) {
func TestTeaSkieselQuote(t *testing.T) { func TestTeaSkieselQuote(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("blah, this is a whole page of explanation where \"we did local search and used a tabu list\" would have sufficed")) c.message(makeMessage("blah, this is a whole page of explanation where \"we did local search and used a tabu list\" would have sufficed"))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 0, item.Count) assert.Equal(t, 0, item.Count)
@ -117,7 +117,7 @@ func TestTeaSkieselQuote(t *testing.T) {
func TestTeaUnicodeJapanese(t *testing.T) { func TestTeaUnicodeJapanese(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("Tea. おちや. Hot.")) c.message(makeMessage("Tea. おちや. Hot."))
item, err := GetItem(mb.DB(), "tester", ":tea:") item, err := GetItem(mb.DB(), "tester", ":tea:")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, item.Count) assert.Equal(t, 1, item.Count)
@ -126,8 +126,8 @@ func TestTeaUnicodeJapanese(t *testing.T) {
func TestResetMe(t *testing.T) { func TestResetMe(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
c.Message(makeMessage("!reset me")) c.message(makeMessage("!reset me"))
items, err := GetItems(mb.DB(), "tester") items, err := GetItems(mb.DB(), "tester")
assert.Nil(t, err) assert.Nil(t, err)
assert.Len(t, items, 0) assert.Len(t, items, 0)
@ -136,7 +136,7 @@ func TestResetMe(t *testing.T) {
func TestCounterOne(t *testing.T) { func TestCounterOne(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, mb.Messages[0], "tester has 1 test.") assert.Equal(t, mb.Messages[0], "tester has 1 test.")
} }
@ -144,7 +144,7 @@ func TestCounterOne(t *testing.T) {
func TestCounterOneWithSpace(t *testing.T) { func TestCounterOneWithSpace(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Message(makeMessage(":test: ++")) c.message(makeMessage(":test: ++"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, mb.Messages[0], "tester has 1 :test:.") assert.Equal(t, mb.Messages[0], "tester has 1 :test:.")
} }
@ -153,7 +153,7 @@ func TestCounterFour(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
} }
assert.Len(t, mb.Messages, 4) assert.Len(t, mb.Messages, 4)
assert.Equal(t, mb.Messages[3], "tester has 4 test.") assert.Equal(t, mb.Messages[3], "tester has 4 test.")
@ -163,10 +163,10 @@ func TestCounterDecrement(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
c.Message(makeMessage("test--")) c.message(makeMessage("test--"))
assert.Len(t, mb.Messages, 5) assert.Len(t, mb.Messages, 5)
assert.Equal(t, mb.Messages[4], "tester has 3 test.") assert.Equal(t, mb.Messages[4], "tester has 3 test.")
} }
@ -175,10 +175,10 @@ func TestFriendCounterDecrement(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("other.test++")) c.message(makeMessage("other.test++"))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("other has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("other has %d test.", i+1))
} }
c.Message(makeMessage("other.test--")) c.message(makeMessage("other.test--"))
assert.Len(t, mb.Messages, 5) assert.Len(t, mb.Messages, 5)
assert.Equal(t, mb.Messages[4], "other has 3 test.") assert.Equal(t, mb.Messages[4], "other has 3 test.")
} }
@ -187,12 +187,12 @@ func TestDecrementZero(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
j := 4 j := 4
for i := 4; i > 0; i-- { for i := 4; i > 0; i-- {
c.Message(makeMessage("test--")) c.message(makeMessage("test--"))
assert.Equal(t, mb.Messages[j], fmt.Sprintf("tester has %d test.", i-1)) assert.Equal(t, mb.Messages[j], fmt.Sprintf("tester has %d test.", i-1))
j++ j++
} }
@ -204,10 +204,10 @@ func TestClear(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
res := c.Message(makeMessage("!clear test")) res := c.message(makeMessage("!clear test"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Actions, 1) assert.Len(t, mb.Actions, 1)
assert.Equal(t, mb.Actions[0], "chops a few test out of his brain") assert.Equal(t, mb.Actions[0], "chops a few test out of his brain")
@ -217,10 +217,10 @@ func TestCount(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
res := c.Message(makeMessage("!count test")) res := c.message(makeMessage("!count test"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 5) assert.Len(t, mb.Messages, 5)
assert.Equal(t, mb.Messages[4], "tester has 4 test.") assert.Equal(t, mb.Messages[4], "tester has 4 test.")
@ -230,18 +230,18 @@ func TestInspectMe(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
c.Message(makeMessage("test++")) c.message(makeMessage("test++"))
assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1)) assert.Equal(t, mb.Messages[i], fmt.Sprintf("tester has %d test.", i+1))
} }
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
c.Message(makeMessage("fucks++")) c.message(makeMessage("fucks++"))
assert.Equal(t, mb.Messages[i+4], fmt.Sprintf("tester has %d fucks.", i+1)) assert.Equal(t, mb.Messages[i+4], fmt.Sprintf("tester has %d fucks.", i+1))
} }
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
c.Message(makeMessage("cheese++")) c.message(makeMessage("cheese++"))
assert.Equal(t, mb.Messages[i+6], fmt.Sprintf("tester has %d cheese.", i+1)) assert.Equal(t, mb.Messages[i+6], fmt.Sprintf("tester has %d cheese.", i+1))
} }
res := c.Message(makeMessage("!inspect me")) res := c.message(makeMessage("!inspect me"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 27) assert.Len(t, mb.Messages, 27)
assert.Equal(t, mb.Messages[26], "tester has the following counters: test: 4, fucks: 2, cheese: 20.") assert.Equal(t, mb.Messages[26], "tester has the following counters: test: 4, fucks: 2, cheese: 20.")
@ -250,22 +250,10 @@ func TestInspectMe(t *testing.T) {
func TestHelp(t *testing.T) { func TestHelp(t *testing.T) {
mb, c := setup(t) mb, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Help("channel", []string{}) c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBotMessage(t *testing.T) {
_, c := setup(t)
assert.NotNil(t, c)
assert.False(t, c.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
_, c := setup(t)
assert.NotNil(t, c)
assert.False(t, c.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
_, c := setup(t) _, c := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)

View File

@ -19,10 +19,13 @@ type DicePlugin struct {
} }
// NewDicePlugin creates a new DicePlugin with the Plugin interface // NewDicePlugin creates a new DicePlugin with the Plugin interface
func New(bot bot.Bot) *DicePlugin { func New(b bot.Bot) *DicePlugin {
return &DicePlugin{ dp := &DicePlugin{
Bot: bot, Bot: b,
} }
b.Register(dp, bot.Message, dp.message)
b.Register(dp, bot.Help, dp.help)
return dp
} }
func rollDie(sides int) int { func rollDie(sides int) int {
@ -32,7 +35,7 @@ func rollDie(sides int) int {
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *DicePlugin) Message(message msg.Message) bool { func (p *DicePlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !message.Command { if !message.Command {
return false return false
} }
@ -46,7 +49,7 @@ func (p *DicePlugin) Message(message msg.Message) bool {
} }
if sides < 2 || nDice < 1 || nDice > 20 { if sides < 2 || nDice < 1 || nDice > 20 {
p.Bot.SendMessage(channel, "You're a dick.") p.Bot.Send(bot.Message, channel, "You're a dick.")
return true return true
} }
@ -61,29 +64,18 @@ func (p *DicePlugin) Message(message msg.Message) bool {
} }
} }
p.Bot.SendMessage(channel, rolls) p.Bot.Send(bot.Message, channel, rolls)
return true return true
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *DicePlugin) Help(channel string, parts []string) { func (p *DicePlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "Roll dice using notation XdY. Try \"3d20\".") p.Bot.Send(bot.Message, message.Channel, "Roll dice using notation XdY. Try \"3d20\".")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *DicePlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *DicePlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *DicePlugin) RegisterWeb() *string { func (p *DicePlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *DicePlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -29,7 +29,7 @@ func TestDie(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!1d6")) res := c.message(makeMessage("!1d6"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "tester, you rolled:") assert.Contains(t, mb.Messages[0], "tester, you rolled:")
@ -39,7 +39,7 @@ func TestDice(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!5d6")) res := c.message(makeMessage("!5d6"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "tester, you rolled:") assert.Contains(t, mb.Messages[0], "tester, you rolled:")
@ -49,7 +49,7 @@ func TestNotCommand(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("1d6")) res := c.message(makeMessage("1d6"))
assert.False(t, res) assert.False(t, res)
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
} }
@ -58,7 +58,7 @@ func TestBadDice(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!aued6")) res := c.message(makeMessage("!aued6"))
assert.False(t, res) assert.False(t, res)
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
} }
@ -67,7 +67,7 @@ func TestBadSides(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!1daoeu")) res := c.message(makeMessage("!1daoeu"))
assert.False(t, res) assert.False(t, res)
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
} }
@ -76,7 +76,7 @@ func TestLotsOfDice(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!100d100")) res := c.message(makeMessage("!100d100"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "You're a dick.") assert.Contains(t, mb.Messages[0], "You're a dick.")
@ -86,24 +86,10 @@ func TestHelp(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Help("channel", []string{}) c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBotMessage(t *testing.T) {
mb := bot.NewMockBot()
c := New(mb)
assert.NotNil(t, c)
assert.False(t, c.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
mb := bot.NewMockBot()
c := New(mb)
assert.NotNil(t, c)
assert.False(t, c.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)

View File

@ -142,9 +142,9 @@ func (p *DowntimePlugin) Message(message msg.Message) bool {
} }
if !entry.id.Valid { if !entry.id.Valid {
// couldn't find em // couldn't find em
p.Bot.SendMessage(channel, fmt.Sprintf("Sorry, I don't know %s.", nick)) p.Bot.Send(bot.Message, channel, fmt.Sprintf("Sorry, I don't know %s.", nick))
} else { } else {
p.Bot.SendMessage(channel, fmt.Sprintf("%s has been idle for: %s", p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s has been idle for: %s",
nick, time.Now().Sub(entry.lastSeen))) nick, time.Now().Sub(entry.lastSeen)))
} }
ret = true ret = true
@ -165,7 +165,7 @@ func (p *DowntimePlugin) Message(message msg.Message) bool {
tops = fmt.Sprintf("%s%s: %s ", tops, e.nick, time.Now().Sub(e.lastSeen)) tops = fmt.Sprintf("%s%s: %s ", tops, e.nick, time.Now().Sub(e.lastSeen))
} }
} }
p.Bot.SendMessage(channel, tops) p.Bot.Send(bot.Message, channel, tops)
ret = true ret = true
} }
@ -197,7 +197,7 @@ func (p *DowntimePlugin) remove(user string) error {
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *DowntimePlugin) Help(channel string, parts []string) { func (p *DowntimePlugin) Help(channel string, parts []string) {
p.Bot.SendMessage(channel, "Ask me how long one of your friends has been idele with, \"idle <nick>\"") p.Bot.Send(bot.Message, channel, "Ask me how long one of your friends has been idele with, \"idle <nick>\"")
} }
// Empty event handler because this plugin does not do anything on event recv // Empty event handler because this plugin does not do anything on event recv

View File

@ -20,7 +20,7 @@ type EmojifyMePlugin struct {
Emoji map[string]string Emoji map[string]string
} }
func New(bot bot.Bot) *EmojifyMePlugin { func New(b bot.Bot) *EmojifyMePlugin {
resp, err := http.Get("https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json") resp, err := http.Get("https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json")
if err != nil { if err != nil {
log.Fatalf("Error generic emoji list: %s", err) log.Fatalf("Error generic emoji list: %s", err)
@ -48,14 +48,16 @@ func New(bot bot.Bot) *EmojifyMePlugin {
} }
} }
return &EmojifyMePlugin{ ep := &EmojifyMePlugin{
Bot: bot, Bot: b,
GotBotEmoji: false, GotBotEmoji: false,
Emoji: emojiMap, Emoji: emojiMap,
} }
b.Register(ep, bot.Message, ep.message)
return ep
} }
func (p *EmojifyMePlugin) Message(message msg.Message) bool { func (p *EmojifyMePlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !p.GotBotEmoji { if !p.GotBotEmoji {
p.GotBotEmoji = true p.GotBotEmoji = true
emojiMap := p.Bot.GetEmojiList() emojiMap := p.Bot.GetEmojiList()
@ -90,22 +92,10 @@ func (p *EmojifyMePlugin) Message(message msg.Message) bool {
if emojied > 0 && rand.Float64() <= p.Bot.Config().GetFloat64("Emojify.Chance", 0.02)*emojied { if emojied > 0 && rand.Float64() <= p.Bot.Config().GetFloat64("Emojify.Chance", 0.02)*emojied {
for _, e := range emojys { for _, e := range emojys {
p.Bot.React(message.Channel, e, message) p.Bot.Send(bot.Reaction, message.Channel, e, message)
}
return true
} }
return false return false
} }
func (p *EmojifyMePlugin) Help(channel string, parts []string) {
}
func (p *EmojifyMePlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *EmojifyMePlugin) BotMessage(message msg.Message) bool {
return false return false
} }
@ -113,8 +103,6 @@ func (p *EmojifyMePlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *EmojifyMePlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }
func stringsContain(haystack []string, needle string) bool { func stringsContain(haystack []string, needle string) bool {
for _, s := range haystack { for _, s := range haystack {
if s == needle { if s == needle {

View File

@ -314,6 +314,9 @@ func New(botInst bot.Bot) *Factoid {
}(channel) }(channel)
} }
botInst.Register(p, bot.Message, p.message)
botInst.Register(p, bot.Help, p.help)
return p return p
} }
@ -405,13 +408,13 @@ func (p *Factoid) sayFact(message msg.Message, fact factoid) {
} }
if fact.Verb == "action" { if fact.Verb == "action" {
p.Bot.SendAction(message.Channel, msg) p.Bot.Send(bot.Action, message.Channel, msg)
} else if fact.Verb == "react" { } else if fact.Verb == "react" {
p.Bot.React(message.Channel, msg, message) p.Bot.Send(bot.Reaction, message.Channel, msg, message)
} else if fact.Verb == "reply" { } else if fact.Verb == "reply" {
p.Bot.SendMessage(message.Channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
} else { } else {
p.Bot.SendMessage(message.Channel, full) p.Bot.Send(bot.Message, message.Channel, full)
} }
} }
@ -457,7 +460,7 @@ func (p *Factoid) tellThemWhatThatWas(message msg.Message) bool {
msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'", msg = fmt.Sprintf("That was (#%d) '%s <%s> %s'",
fact.id.Int64, fact.Fact, fact.Verb, fact.Tidbit) fact.id.Int64, fact.Fact, fact.Verb, fact.Tidbit)
} }
p.Bot.SendMessage(message.Channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
return true return true
} }
@ -475,21 +478,21 @@ func (p *Factoid) learnAction(message msg.Message, action string) bool {
action = strings.TrimSpace(action) action = strings.TrimSpace(action)
if len(trigger) == 0 || len(fact) == 0 || len(action) == 0 { if len(trigger) == 0 || len(fact) == 0 || len(action) == 0 {
p.Bot.SendMessage(message.Channel, "I don't want to learn that.") p.Bot.Send(bot.Message, message.Channel, "I don't want to learn that.")
return true return true
} }
if len(strings.Split(fact, "$and")) > 4 { if len(strings.Split(fact, "$and")) > 4 {
p.Bot.SendMessage(message.Channel, "You can't use more than 4 $and operators.") p.Bot.Send(bot.Message, message.Channel, "You can't use more than 4 $and operators.")
return true return true
} }
strippedaction := strings.Replace(strings.Replace(action, "<", "", 1), ">", "", 1) strippedaction := strings.Replace(strings.Replace(action, "<", "", 1), ">", "", 1)
if err := p.learnFact(message, trigger, strippedaction, fact); err != nil { if err := p.learnFact(message, trigger, strippedaction, fact); err != nil {
p.Bot.SendMessage(message.Channel, err.Error()) p.Bot.Send(bot.Message, message.Channel, err.Error())
} else { } else {
p.Bot.SendMessage(message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name)) p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("Okay, %s.", message.User.Name))
} }
return true return true
@ -509,7 +512,7 @@ func changeOperator(body string) string {
// an admin, it may be deleted // an admin, it may be deleted
func (p *Factoid) forgetLastFact(message msg.Message) bool { func (p *Factoid) forgetLastFact(message msg.Message) bool {
if p.LastFact == nil { if p.LastFact == nil {
p.Bot.SendMessage(message.Channel, "I refuse.") p.Bot.Send(bot.Message, message.Channel, "I refuse.")
return true return true
} }
@ -519,7 +522,7 @@ func (p *Factoid) forgetLastFact(message msg.Message) bool {
} }
fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.id.Int64, p.LastFact.Fact, fmt.Printf("Forgot #%d: %s %s %s\n", p.LastFact.id.Int64, p.LastFact.Fact,
p.LastFact.Verb, p.LastFact.Tidbit) p.LastFact.Verb, p.LastFact.Tidbit)
p.Bot.SendAction(message.Channel, "hits himself over the head with a skillet") p.Bot.Send(bot.Action, message.Channel, "hits himself over the head with a skillet")
p.LastFact = nil p.LastFact = nil
return true return true
@ -539,7 +542,7 @@ func (p *Factoid) changeFact(message msg.Message) bool {
if len(parts) == 4 { if len(parts) == 4 {
// replacement // replacement
if parts[0] != "s" { if parts[0] != "s" {
p.Bot.SendMessage(message.Channel, "Nah.") p.Bot.Send(bot.Message, message.Channel, "Nah.")
} }
find := parts[1] find := parts[1]
replace := parts[2] replace := parts[2]
@ -554,10 +557,10 @@ func (p *Factoid) changeFact(message msg.Message) bool {
} }
// make the changes // make the changes
msg := fmt.Sprintf("Changing %d facts.", len(result)) msg := fmt.Sprintf("Changing %d facts.", len(result))
p.Bot.SendMessage(message.Channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
reg, err := regexp.Compile(find) reg, err := regexp.Compile(find)
if err != nil { if err != nil {
p.Bot.SendMessage(message.Channel, "I don't really want to.") p.Bot.Send(bot.Message, message.Channel, "I don't really want to.")
return false return false
} }
for _, fact := range result { for _, fact := range result {
@ -574,12 +577,12 @@ func (p *Factoid) changeFact(message msg.Message) bool {
result, err := getFacts(p.db, trigger, parts[1]) result, err := getFacts(p.db, trigger, parts[1])
if err != nil { if err != nil {
log.Println("Error getting facts: ", trigger, err) log.Println("Error getting facts: ", trigger, err)
p.Bot.SendMessage(message.Channel, "bzzzt") p.Bot.Send(bot.Message, message.Channel, "bzzzt")
return true return true
} }
count := len(result) count := len(result)
if count == 0 { if count == 0 {
p.Bot.SendMessage(message.Channel, "I didn't find any facts like that.") p.Bot.Send(bot.Message, message.Channel, "I didn't find any facts like that.")
return true return true
} }
if parts[2] == "g" && len(result) > 4 { if parts[2] == "g" && len(result) > 4 {
@ -599,9 +602,9 @@ func (p *Factoid) changeFact(message msg.Message) bool {
if count > 4 { if count > 4 {
msg = fmt.Sprintf("%s | ...and %d others", msg, count) msg = fmt.Sprintf("%s | ...and %d others", msg, count)
} }
p.Bot.SendMessage(message.Channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
} else { } else {
p.Bot.SendMessage(message.Channel, "I don't know what you mean.") p.Bot.Send(bot.Message, message.Channel, "I don't know what you mean.")
} }
return true return true
} }
@ -609,7 +612,7 @@ func (p *Factoid) changeFact(message msg.Message) bool {
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *Factoid) Message(message msg.Message) bool { func (p *Factoid) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "what was that?" { if strings.ToLower(message.Body) == "what was that?" {
return p.tellThemWhatThatWas(message) return p.tellThemWhatThatWas(message)
} }
@ -625,14 +628,14 @@ func (p *Factoid) Message(message msg.Message) bool {
m := strings.TrimPrefix(message.Body, "alias ") m := strings.TrimPrefix(message.Body, "alias ")
parts := strings.SplitN(m, "->", 2) parts := strings.SplitN(m, "->", 2)
if len(parts) != 2 { if len(parts) != 2 {
p.Bot.SendMessage(message.Channel, "If you want to alias something, use: `alias this -> that`") p.Bot.Send(bot.Message, message.Channel, "If you want to alias something, use: `alias this -> that`")
return true return true
} }
a := aliasFromStrings(strings.TrimSpace(parts[1]), strings.TrimSpace(parts[0])) a := aliasFromStrings(strings.TrimSpace(parts[1]), strings.TrimSpace(parts[0]))
if err := a.save(p.db); err != nil { if err := a.save(p.db); err != nil {
p.Bot.SendMessage(message.Channel, err.Error()) p.Bot.Send(bot.Message, message.Channel, err.Error())
} else { } else {
p.Bot.SendAction(message.Channel, "learns a new synonym") p.Bot.Send(bot.Action, message.Channel, "learns a new synonym")
} }
return true return true
} }
@ -664,19 +667,15 @@ func (p *Factoid) Message(message msg.Message) bool {
} }
// We didn't find anything, panic! // We didn't find anything, panic!
p.Bot.SendMessage(message.Channel, p.NotFound[rand.Intn(len(p.NotFound))]) p.Bot.Send(bot.Message, message.Channel, p.NotFound[rand.Intn(len(p.NotFound))])
return true return true
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *Factoid) Help(channel string, parts []string) { func (p *Factoid) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he <has> $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.") p.Bot.Send(bot.Message, message.Channel, "I can learn facts and spit them back out. You can say \"this is that\" or \"he <has> $5\". Later, trigger the factoid by just saying the trigger word, \"this\" or \"he\" in these examples.")
p.Bot.SendMessage(channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.") p.Bot.Send(bot.Message, message.Channel, "I can also figure out some variables including: $nonzero, $digit, $nick, and $someone.")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *Factoid) Event(kind string, message msg.Message) bool {
return false
} }
// Pull a fact at random from the database // Pull a fact at random from the database
@ -737,11 +736,6 @@ func (p *Factoid) factTimer(channel string) {
} }
} }
// Handler for bot's own messages
func (p *Factoid) BotMessage(message msg.Message) bool {
return false
}
// Register any web URLs desired // Register any web URLs desired
func (p *Factoid) RegisterWeb() *string { func (p *Factoid) RegisterWeb() *string {
http.HandleFunc("/factoid/req", p.serveQuery) http.HandleFunc("/factoid/req", p.serveQuery)
@ -784,5 +778,3 @@ func (p *Factoid) serveQuery(w http.ResponseWriter, r *http.Request) {
log.Println(err) log.Println(err)
} }
} }
func (p *Factoid) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -29,6 +29,8 @@ func NewRemember(b bot.Bot) *RememberPlugin {
Log: make(map[string][]msg.Message), Log: make(map[string][]msg.Message),
db: b.DB(), db: b.DB(),
} }
b.Register(p, bot.Message, p.message)
b.Register(p, bot.Message, p.help)
return &p return &p
} }
@ -36,11 +38,11 @@ func NewRemember(b bot.Bot) *RememberPlugin {
// This function returns true if the plugin responds in a meaningful way to the // 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 // users message. Otherwise, the function returns false and the bot continues
// execution of other plugins. // execution of other plugins.
func (p *RememberPlugin) Message(message msg.Message) bool { func (p *RememberPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "quote" && message.Command { if strings.ToLower(message.Body) == "quote" && message.Command {
q := p.randQuote() q := p.randQuote()
p.Bot.SendMessage(message.Channel, q) p.Bot.Send(bot.Message, message.Channel, q)
// is it evil not to remember that the user said quote? // is it evil not to remember that the user said quote?
return true return true
@ -87,7 +89,7 @@ func (p *RememberPlugin) Message(message msg.Message) bool {
} }
if err := fact.save(p.db); err != nil { if err := fact.save(p.db); err != nil {
log.Println("ERROR!!!!:", err) log.Println("ERROR!!!!:", err)
p.Bot.SendMessage(message.Channel, "Tell somebody I'm broke.") p.Bot.Send(bot.Message, message.Channel, "Tell somebody I'm broke.")
} }
log.Println("Remembering factoid:", msg) log.Println("Remembering factoid:", msg)
@ -95,14 +97,14 @@ func (p *RememberPlugin) Message(message msg.Message) bool {
// sorry, not creative with names so we're reusing msg // sorry, not creative with names so we're reusing msg
msg = fmt.Sprintf("Okay, %s, remembering '%s'.", msg = fmt.Sprintf("Okay, %s, remembering '%s'.",
message.User.Name, msg) message.User.Name, msg)
p.Bot.SendMessage(message.Channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
p.recordMsg(message) p.recordMsg(message)
return true return true
} }
} }
p.Bot.SendMessage(message.Channel, "Sorry, I don't know that phrase.") p.Bot.Send(bot.Message, message.Channel, "Sorry, I don't know that phrase.")
p.recordMsg(message) p.recordMsg(message)
return true return true
} }
@ -111,14 +113,15 @@ func (p *RememberPlugin) Message(message msg.Message) bool {
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *RememberPlugin) Help(channel string, parts []string) { func (p *RememberPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
msg := "!remember will let you quote your idiot friends. Just type " + msg := "!remember will let you quote your idiot friends. Just type " +
"!remember <nick> <snippet> to remember what they said. Snippet can " + "!remember <nick> <snippet> to remember what they said. Snippet can " +
"be any part of their message. Later on, you can ask for a random " + "be any part of their message. Later on, you can ask for a random " +
"!quote." "!quote."
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
return true
} }
// deliver a random quote out of the db. // deliver a random quote out of the db.
@ -150,19 +153,8 @@ func (p *RememberPlugin) randQuote() string {
return f.Tidbit return f.Tidbit
} }
// Empty event handler because this plugin does not do anything on event recv
func (p *RememberPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Record what the bot says in the log
func (p *RememberPlugin) BotMessage(message msg.Message) bool {
p.recordMsg(message)
return false
}
// Register any web URLs desired // Register any web URLs desired
func (p *RememberPlugin) RegisterWeb() *string { func (p RememberPlugin) RegisterWeb() *string {
return nil return nil
} }
@ -170,5 +162,3 @@ func (p *RememberPlugin) recordMsg(message msg.Message) {
log.Printf("Logging message: %s: %s", message.User.Name, message.Body) log.Printf("Logging message: %s: %s", message.User.Name, message.Body)
p.Log[message.Channel] = append(p.Log[message.Channel], message) p.Log[message.Channel] = append(p.Log[message.Channel], message)
} }
func (p *RememberPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -42,7 +42,7 @@ func TestCornerCaseBug(t *testing.T) {
p, _, mb := makePlugin(t) p, _, mb := makePlugin(t)
for _, m := range msgs { for _, m := range msgs {
p.Message(m) p.message(bot.Message, m)
} }
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "horse dick") assert.Contains(t, mb.Messages[0], "horse dick")
@ -59,7 +59,7 @@ func TestReact(t *testing.T) {
_, p, mb := makePlugin(t) _, p, mb := makePlugin(t)
for _, m := range msgs { for _, m := range msgs {
p.Message(m) p.message(bot.Message, m)
} }
assert.Len(t, mb.Reactions, 1) assert.Len(t, mb.Reactions, 1)
assert.Contains(t, mb.Reactions[0], "jesus") assert.Contains(t, mb.Reactions[0], "jesus")
@ -72,7 +72,7 @@ func TestReactCantLearnSpaces(t *testing.T) {
_, p, mb := makePlugin(t) _, p, mb := makePlugin(t)
for _, m := range msgs { for _, m := range msgs {
p.Message(m) p.message(bot.Message, m)
} }
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "not a valid") assert.Contains(t, mb.Messages[0], "not a valid")

View File

@ -66,11 +66,14 @@ func New(b bot.Bot) *FirstPlugin {
log.Fatal("Could not initialize first plugin: ", err) log.Fatal("Could not initialize first plugin: ", err)
} }
return &FirstPlugin{ fp := &FirstPlugin{
Bot: b, Bot: b,
db: b.DB(), db: b.DB(),
First: first, First: first,
} }
b.Register(fp, bot.Message, fp.message)
b.Register(fp, bot.Help, fp.help)
return fp
} }
func getLastFirst(db *sqlx.DB) (*FirstEntry, error) { func getLastFirst(db *sqlx.DB) (*FirstEntry, error) {
@ -123,7 +126,7 @@ func isToday(t time.Time) bool {
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *FirstPlugin) Message(message msg.Message) bool { func (p *FirstPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
// This bot does not reply to anything // This bot does not reply to anything
if p.First == nil && p.allowed(message) { if p.First == nil && p.allowed(message) {
@ -195,7 +198,7 @@ func (p *FirstPlugin) recordFirst(message msg.Message) {
func (p *FirstPlugin) announceFirst(message msg.Message) { func (p *FirstPlugin) announceFirst(message msg.Message) {
c := message.Channel c := message.Channel
if p.First != nil { if p.First != nil {
p.Bot.SendMessage(c, fmt.Sprintf("%s had first at %s with the message: \"%s\"", p.Bot.Send(bot.Message, c, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
p.First.nick, p.First.time.Format("15:04"), p.First.body)) p.First.nick, p.First.time.Format("15:04"), p.First.body))
} }
} }
@ -208,23 +211,12 @@ func (p *FirstPlugin) LoadData() {
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *FirstPlugin) Help(channel string, parts []string) { func (p *FirstPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "Sorry, First does not do a goddamn thing.") p.Bot.Send(bot.Message, message.Channel, "Sorry, First does not do a goddamn thing.")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *FirstPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *FirstPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *FirstPlugin) RegisterWeb() *string { func (p *FirstPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *FirstPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -24,8 +24,8 @@ type InventoryPlugin struct {
} }
// New creates a new InventoryPlugin with the Plugin interface // New creates a new InventoryPlugin with the Plugin interface
func New(bot bot.Bot) *InventoryPlugin { func New(b bot.Bot) *InventoryPlugin {
config := bot.Config() config := b.Config()
nick := config.Get("nick", "bot") nick := config.Get("nick", "bot")
r1, err := regexp.Compile("take this (.+)") r1, err := regexp.Compile("take this (.+)")
checkerr(err) checkerr(err)
@ -38,15 +38,15 @@ func New(bot bot.Bot) *InventoryPlugin {
r5, err := regexp.Compile(fmt.Sprintf("gives (.+) to %s([^a-zA-Z].*)?", nick)) r5, err := regexp.Compile(fmt.Sprintf("gives (.+) to %s([^a-zA-Z].*)?", nick))
checkerr(err) checkerr(err)
p := InventoryPlugin{ p := &InventoryPlugin{
DB: bot.DB(), DB: b.DB(),
bot: bot, bot: b,
config: config, config: config,
r1: r1, r2: r2, r3: r3, r4: r4, r5: r5, r1: r1, r2: r2, r3: r3, r4: r4, r5: r5,
} }
bot.RegisterFilter("$item", p.itemFilter) b.RegisterFilter("$item", p.itemFilter)
bot.RegisterFilter("$giveitem", p.giveItemFilter) b.RegisterFilter("$giveitem", p.giveItemFilter)
_, err = p.DB.Exec(`create table if not exists inventory ( _, err = p.DB.Exec(`create table if not exists inventory (
item string primary key item string primary key
@ -56,7 +56,9 @@ func New(bot bot.Bot) *InventoryPlugin {
log.Fatal(err) log.Fatal(err)
} }
return &p b.Register(p, bot.Message, p.message)
return p
} }
func (p *InventoryPlugin) giveItemFilter(input string) string { func (p *InventoryPlugin) giveItemFilter(input string) string {
@ -75,7 +77,7 @@ func (p *InventoryPlugin) itemFilter(input string) string {
return input return input
} }
func (p *InventoryPlugin) Message(message msg.Message) bool { func (p *InventoryPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
m := message.Body m := message.Body
log.Printf("inventory trying to read %+v", message) log.Printf("inventory trying to read %+v", message)
if message.Command { if message.Command {
@ -86,7 +88,7 @@ func (p *InventoryPlugin) Message(message msg.Message) bool {
log.Printf("I think I have more than 0 items: %+v, len(items)=%d", items, len(items)) log.Printf("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, ", ")) say = fmt.Sprintf("I'm currently holding %s", strings.Join(items, ", "))
} }
p.bot.SendMessage(message.Channel, say) p.bot.Send(bot.Message, message.Channel, say)
return true return true
} }
@ -197,7 +199,7 @@ func (p *InventoryPlugin) remove(i string) {
func (p *InventoryPlugin) addItem(m msg.Message, i string) bool { func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
if p.exists(i) { if p.exists(i) {
p.bot.SendMessage(m.Channel, fmt.Sprintf("I already have %s.", i)) p.bot.Send(bot.Message, m.Channel, fmt.Sprintf("I already have %s.", i))
return true return true
} }
var removed string var removed string
@ -210,9 +212,9 @@ func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
log.Printf("Error inserting new inventory item: %s", err) log.Printf("Error inserting new inventory item: %s", err)
} }
if removed != "" { if removed != "" {
p.bot.SendAction(m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name)) p.bot.Send(bot.Action, m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name))
} else { } else {
p.bot.SendAction(m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name)) p.bot.Send(bot.Action, m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name))
} }
return true return true
} }
@ -223,20 +225,7 @@ func checkerr(e error) {
} }
} }
func (p *InventoryPlugin) Event(e string, message msg.Message) bool {
return false
}
func (p *InventoryPlugin) BotMessage(message msg.Message) bool {
return false
}
func (p *InventoryPlugin) Help(e string, m []string) {
}
func (p *InventoryPlugin) RegisterWeb() *string { func (p *InventoryPlugin) RegisterWeb() *string {
// nothing to register // nothing to register
return nil return nil
} }
func (p *InventoryPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -20,19 +20,20 @@ type LeftpadPlugin struct {
} }
// New creates a new LeftpadPlugin with the Plugin interface // New creates a new LeftpadPlugin with the Plugin interface
func New(bot bot.Bot) *LeftpadPlugin { func New(b bot.Bot) *LeftpadPlugin {
p := LeftpadPlugin{ p := &LeftpadPlugin{
bot: bot, bot: b,
config: bot.Config(), config: b.Config(),
} }
return &p b.Register(p, bot.Message, p.message)
return p
} }
type leftpadResp struct { type leftpadResp struct {
Str string Str string
} }
func (p *LeftpadPlugin) Message(message msg.Message) bool { func (p *LeftpadPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !message.Command { if !message.Command {
return false return false
} }
@ -42,40 +43,27 @@ func (p *LeftpadPlugin) Message(message msg.Message) bool {
padchar := parts[1] padchar := parts[1]
length, err := strconv.Atoi(parts[2]) length, err := strconv.Atoi(parts[2])
if err != nil { if err != nil {
p.bot.SendMessage(message.Channel, "Invalid padding number") p.bot.Send(bot.Message, message.Channel, "Invalid padding number")
return true return true
} }
maxLen, who := p.config.GetInt("LeftPad.MaxLen", 50), p.config.Get("LeftPad.Who", "Putin") maxLen, who := p.config.GetInt("LeftPad.MaxLen", 50), p.config.Get("LeftPad.Who", "Putin")
if length > maxLen && maxLen > 0 { if length > maxLen && maxLen > 0 {
msg := fmt.Sprintf("%s would kill me if I did that.", who) msg := fmt.Sprintf("%s would kill me if I did that.", who)
p.bot.SendMessage(message.Channel, msg) p.bot.Send(bot.Message, message.Channel, msg)
return true return true
} }
text := strings.Join(parts[3:], " ") text := strings.Join(parts[3:], " ")
res := leftpad.LeftPad(text, length, padchar) res := leftpad.LeftPad(text, length, padchar)
p.bot.SendMessage(message.Channel, res) p.bot.Send(bot.Message, message.Channel, res)
return true return true
} }
return false return false
} }
func (p *LeftpadPlugin) Event(e string, message msg.Message) bool {
return false
}
func (p *LeftpadPlugin) BotMessage(message msg.Message) bool {
return false
}
func (p *LeftpadPlugin) Help(e string, m []string) {
}
func (p *LeftpadPlugin) RegisterWeb() *string { func (p *LeftpadPlugin) RegisterWeb() *string {
// nothing to register // nothing to register
return nil return nil
} }
func (p *LeftpadPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -13,12 +13,12 @@ import (
"github.com/velour/catbase/plugins/counter" "github.com/velour/catbase/plugins/counter"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -37,28 +37,28 @@ func makePlugin(t *testing.T) (*LeftpadPlugin, *bot.MockBot) {
func TestLeftpad(t *testing.T) { func TestLeftpad(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.Message(makeMessage("!leftpad test 8 test")) p.message(makeMessage("!leftpad test 8 test"))
assert.Contains(t, mb.Messages[0], "testtest") assert.Contains(t, mb.Messages[0], "testtest")
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBadNumber(t *testing.T) { func TestBadNumber(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.Message(makeMessage("!leftpad test fuck test")) p.message(makeMessage("!leftpad test fuck test"))
assert.Contains(t, mb.Messages[0], "Invalid") assert.Contains(t, mb.Messages[0], "Invalid")
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestNotCommand(t *testing.T) { func TestNotCommand(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.Message(makeMessage("leftpad test fuck test")) p.message(makeMessage("leftpad test fuck test"))
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
} }
func TestNoMaxLen(t *testing.T) { func TestNoMaxLen(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.config.Set("LeftPad.MaxLen", "0") p.config.Set("LeftPad.MaxLen", "0")
p.Message(makeMessage("!leftpad dicks 100 dicks")) p.message(makeMessage("!leftpad dicks 100 dicks"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "dicks") assert.Contains(t, mb.Messages[0], "dicks")
} }
@ -67,7 +67,7 @@ func Test50Padding(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.config.Set("LeftPad.MaxLen", "50") p.config.Set("LeftPad.MaxLen", "50")
assert.Equal(t, 50, p.config.GetInt("LeftPad.MaxLen", 100)) assert.Equal(t, 50, p.config.GetInt("LeftPad.MaxLen", 100))
p.Message(makeMessage("!leftpad dicks 100 dicks")) p.message(makeMessage("!leftpad dicks 100 dicks"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "kill me") assert.Contains(t, mb.Messages[0], "kill me")
} }
@ -75,33 +75,17 @@ func Test50Padding(t *testing.T) {
func TestUnder50Padding(t *testing.T) { func TestUnder50Padding(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.config.Set("LeftPad.MaxLen", "50") p.config.Set("LeftPad.MaxLen", "50")
p.Message(makeMessage("!leftpad dicks 49 dicks")) p.message(makeMessage("!leftpad dicks 49 dicks"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "dicks") assert.Contains(t, mb.Messages[0], "dicks")
} }
func TestNotPadding(t *testing.T) { func TestNotPadding(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.Message(makeMessage("!lololol")) p.message(makeMessage("!lololol"))
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
} }
func TestHelp(t *testing.T) {
p, mb := makePlugin(t)
p.Help("channel", []string{})
assert.Len(t, mb.Messages, 0)
}
func TestBotMessage(t *testing.T) {
p, _ := makePlugin(t)
assert.False(t, p.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
p, _ := makePlugin(t)
assert.False(t, p.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
p, _ := makePlugin(t) p, _ := makePlugin(t)
assert.Nil(t, p.RegisterWeb()) assert.Nil(t, p.RegisterWeb())

View File

@ -27,17 +27,20 @@ type NerdepediaPlugin struct {
} }
// NewNerdepediaPlugin creates a new NerdepediaPlugin with the Plugin interface // NewNerdepediaPlugin creates a new NerdepediaPlugin with the Plugin interface
func New(bot bot.Bot) *NerdepediaPlugin { func New(b bot.Bot) *NerdepediaPlugin {
return &NerdepediaPlugin{ np := &NerdepediaPlugin{
bot: bot, bot: b,
config: bot.Config(), config: b.Config(),
} }
b.Register(np, bot.Message, np.message)
b.Register(np, bot.Help, np.help)
return np
} }
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *NerdepediaPlugin) Message(message msg.Message) bool { func (p *NerdepediaPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
lowerCase := strings.ToLower(message.Body) lowerCase := strings.ToLower(message.Body)
query := "" query := ""
if lowerCase == "may the force be with you" || lowerCase == "help me obi-wan" { if lowerCase == "may the force be with you" || lowerCase == "help me obi-wan" {
@ -78,7 +81,7 @@ func (p *NerdepediaPlugin) Message(message msg.Message) bool {
} }
if description != "" && link != "" { if description != "" && link != "" {
p.bot.SendMessage(message.Channel, fmt.Sprintf("%s (%s)", description, link)) p.bot.Send(bot.Message, message.Channel, fmt.Sprintf("%s (%s)", description, link))
return true return true
} }
} }
@ -87,23 +90,12 @@ func (p *NerdepediaPlugin) Message(message msg.Message) bool {
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *NerdepediaPlugin) Help(channel string, parts []string) { func (p *NerdepediaPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.SendMessage(channel, "nerd stuff") p.bot.Send(bot.Message, message.Channel, "nerd stuff")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *NerdepediaPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *NerdepediaPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *NerdepediaPlugin) RegisterWeb() *string { func (p *NerdepediaPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *NerdepediaPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -29,7 +29,7 @@ func TestWars(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("help me obi-wan")) res := c.message(makeMessage("help me obi-wan"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
} }
@ -38,7 +38,7 @@ func TestTrek(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("live long and prosper")) res := c.message(makeMessage("live long and prosper"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
} }
@ -47,7 +47,7 @@ func TestDune(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("bless the maker")) res := c.message(makeMessage("bless the maker"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
} }
@ -56,7 +56,7 @@ func TestPoke(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("gotta catch em all")) res := c.message(makeMessage("gotta catch em all"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
} }

View File

@ -20,30 +20,33 @@ type PickerPlugin struct {
} }
// NewPickerPlugin creates a new PickerPlugin with the Plugin interface // NewPickerPlugin creates a new PickerPlugin with the Plugin interface
func New(bot bot.Bot) *PickerPlugin { func New(b bot.Bot) *PickerPlugin {
return &PickerPlugin{ pp := &PickerPlugin{
Bot: bot, Bot: b,
} }
b.Register(pp, bot.Message, pp.message)
b.Register(pp, bot.Help, pp.help)
return pp
} }
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *PickerPlugin) Message(message msg.Message) bool { func (p *PickerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if !strings.HasPrefix(message.Body, "pick") { if !strings.HasPrefix(message.Body, "pick") {
return false return false
} }
n, items, err := p.parse(message.Body) n, items, err := p.parse(message.Body)
if err != nil { if err != nil {
p.Bot.SendMessage(message.Channel, err.Error()) p.Bot.Send(bot.Message, message.Channel, err.Error())
return true return true
} }
if n == 1 { if n == 1 {
item := items[rand.Intn(len(items))] item := items[rand.Intn(len(items))]
out := fmt.Sprintf("I've chosen %q for you.", strings.TrimSpace(item)) out := fmt.Sprintf("I've chosen %q for you.", strings.TrimSpace(item))
p.Bot.SendMessage(message.Channel, out) p.Bot.Send(bot.Message, message.Channel, out)
return true return true
} }
@ -59,7 +62,7 @@ func (p *PickerPlugin) Message(message msg.Message) bool {
fmt.Fprintf(&b, ", %q", item) fmt.Fprintf(&b, ", %q", item)
} }
b.WriteString(" }") b.WriteString(" }")
p.Bot.SendMessage(message.Channel, b.String()) p.Bot.Send(bot.Message, message.Channel, b.String())
return true return true
} }
@ -108,18 +111,9 @@ func (p *PickerPlugin) parse(body string) (int, []string, error) {
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *PickerPlugin) Help(channel string, parts []string) { func (p *PickerPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "Choose from a list of options. Try \"pick {a,b,c}\".") p.Bot.Send(bot.Message, message.Channel, "Choose from a list of options. Try \"pick {a,b,c}\".")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *PickerPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *PickerPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -29,7 +29,7 @@ func TestPick2(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!pick 2 { a, b,c}")) res := c.message(makeMessage("!pick 2 { a, b,c}"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
if !res { if !res {
t.Fatalf("expected a successful choice, got %q", mb.Messages[0]) t.Fatalf("expected a successful choice, got %q", mb.Messages[0])
@ -40,7 +40,7 @@ func TestPickDefault(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
_ = c.Message(makeMessage("!pick { a}")) _ = c.message(makeMessage("!pick { a}"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, `I've chosen "a" for you.`, mb.Messages[0]) assert.Equal(t, `I've chosen "a" for you.`, mb.Messages[0])
} }

View File

@ -15,14 +15,16 @@ type ReactionPlugin struct {
Config *config.Config Config *config.Config
} }
func New(bot bot.Bot) *ReactionPlugin { func New(b bot.Bot) *ReactionPlugin {
return &ReactionPlugin{ rp := &ReactionPlugin{
Bot: bot, Bot: b,
Config: bot.Config(), Config: b.Config(),
} }
b.Register(rp, bot.Message, rp.message)
return rp
} }
func (p *ReactionPlugin) Message(message msg.Message) bool { func (p *ReactionPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
harrass := false 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 { if message.User.Name == nick {
@ -56,26 +58,12 @@ func (p *ReactionPlugin) Message(message msg.Message) bool {
reaction = p.Config.GetArray("Reaction.NegativeReactions", []string{})[index] reaction = p.Config.GetArray("Reaction.NegativeReactions", []string{})[index]
} }
p.Bot.React(message.Channel, reaction, message) p.Bot.Send(bot.Reaction, message.Channel, reaction, message)
} }
return false return false
} }
func (p *ReactionPlugin) Help(channel string, parts []string) {
}
func (p *ReactionPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *ReactionPlugin) BotMessage(message msg.Message) bool {
return false
}
func (p *ReactionPlugin) RegisterWeb() *string { func (p *ReactionPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *ReactionPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -38,9 +38,9 @@ type Reminder struct {
channel string channel string
} }
func New(bot bot.Bot) *ReminderPlugin { func New(b bot.Bot) *ReminderPlugin {
log.SetFlags(log.LstdFlags | log.Lshortfile) log.SetFlags(log.LstdFlags | log.Lshortfile)
if _, err := bot.DB().Exec(`create table if not exists reminders ( if _, err := b.DB().Exec(`create table if not exists reminders (
id integer primary key, id integer primary key,
fromWho string, fromWho string,
toWho string, toWho string,
@ -56,21 +56,24 @@ func New(bot bot.Bot) *ReminderPlugin {
timer.Stop() timer.Stop()
plugin := &ReminderPlugin{ plugin := &ReminderPlugin{
Bot: bot, Bot: b,
db: bot.DB(), db: b.DB(),
mutex: &sync.Mutex{}, mutex: &sync.Mutex{},
timer: timer, timer: timer,
config: bot.Config(), config: b.Config(),
} }
plugin.queueUpNextReminder() plugin.queueUpNextReminder()
go reminderer(plugin) go reminderer(plugin)
b.Register(plugin, bot.Message, plugin.message)
b.Register(plugin, bot.Help, plugin.help)
return plugin return plugin
} }
func (p *ReminderPlugin) Message(message msg.Message) bool { func (p *ReminderPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
channel := message.Channel channel := message.Channel
from := message.User.Name from := message.User.Name
@ -85,7 +88,7 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
dur, err := time.ParseDuration(parts[3]) dur, err := time.ParseDuration(parts[3])
if err != nil { if err != nil {
p.Bot.SendMessage(channel, "Easy cowboy, not sure I can parse that duration.") p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I can parse that duration.")
return true return true
} }
@ -113,7 +116,7 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
//remind who every dur for dur2 blah //remind who every dur for dur2 blah
dur2, err := time.ParseDuration(parts[5]) dur2, err := time.ParseDuration(parts[5])
if err != nil { if err != nil {
p.Bot.SendMessage(channel, "Easy cowboy, not sure I can parse that duration.") p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I can parse that duration.")
return true return true
} }
@ -124,7 +127,7 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
max := p.config.GetInt("Reminder.MaxBatchAdd", 10) max := p.config.GetInt("Reminder.MaxBatchAdd", 10)
for i := 0; when.Before(endTime); i++ { for i := 0; when.Before(endTime); i++ {
if i >= max { if i >= max {
p.Bot.SendMessage(channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.") p.Bot.Send(bot.Message, channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.")
doConfirm = false doConfirm = false
break break
} }
@ -141,14 +144,14 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
when = when.Add(dur) when = when.Add(dur)
} }
} else { } else {
p.Bot.SendMessage(channel, "Easy cowboy, not sure I comprehend what you're asking.") p.Bot.Send(bot.Message, channel, "Easy cowboy, not sure I comprehend what you're asking.")
return true return true
} }
if doConfirm && from == who { if doConfirm && from == who {
p.Bot.SendMessage(channel, fmt.Sprintf("Okay. I'll remind you.")) p.Bot.Send(bot.Message, channel, fmt.Sprintf("Okay. I'll remind you."))
} else if doConfirm { } else if doConfirm {
p.Bot.SendMessage(channel, fmt.Sprintf("Sure %s, I'll remind %s.", from, who)) p.Bot.Send(bot.Message, channel, fmt.Sprintf("Sure %s, I'll remind %s.", from, who))
} }
p.queueUpNextReminder() p.queueUpNextReminder()
@ -168,22 +171,22 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
} }
} }
if err != nil { if err != nil {
p.Bot.SendMessage(channel, "listing failed.") p.Bot.Send(bot.Message, channel, "listing failed.")
} else { } else {
p.Bot.SendMessage(channel, response) p.Bot.Send(bot.Message, channel, response)
} }
return true return true
} else if len(parts) == 3 && strings.ToLower(parts[0]) == "cancel" && strings.ToLower(parts[1]) == "reminder" { } else if len(parts) == 3 && strings.ToLower(parts[0]) == "cancel" && strings.ToLower(parts[1]) == "reminder" {
id, err := strconv.ParseInt(parts[2], 10, 64) id, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil { if err != nil {
p.Bot.SendMessage(channel, fmt.Sprintf("couldn't parse id: %s", parts[2])) p.Bot.Send(bot.Message, channel, fmt.Sprintf("couldn't parse id: %s", parts[2]))
} else { } else {
err := p.deleteReminder(id) err := p.deleteReminder(id)
if err == nil { if err == nil {
p.Bot.SendMessage(channel, fmt.Sprintf("successfully canceled reminder: %s", parts[2])) p.Bot.Send(bot.Message, channel, fmt.Sprintf("successfully canceled reminder: %s", parts[2]))
} else { } else {
p.Bot.SendMessage(channel, fmt.Sprintf("failed to find and cancel reminder: %s", parts[2])) p.Bot.Send(bot.Message, channel, fmt.Sprintf("failed to find and cancel reminder: %s", parts[2]))
} }
} }
return true return true
@ -192,16 +195,9 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
return false return false
} }
func (p *ReminderPlugin) Help(channel string, parts []string) { func (p *ReminderPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "Pester someone with a reminder. Try \"remind <user> in <duration> message\".\n\nUnsure about duration syntax? Check https://golang.org/pkg/time/#ParseDuration") p.Bot.Send(bot.Message, message.Channel, "Pester someone with a reminder. Try \"remind <user> in <duration> message\".\n\nUnsure about duration syntax? Check https://golang.org/pkg/time/#ParseDuration")
} return true
func (p *ReminderPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *ReminderPlugin) BotMessage(message msg.Message) bool {
return false
} }
func (p *ReminderPlugin) RegisterWeb() *string { func (p *ReminderPlugin) RegisterWeb() *string {
@ -353,7 +349,7 @@ func reminderer(p *ReminderPlugin) {
message = fmt.Sprintf("Hey %s, %s wanted you to be reminded: %s", reminder.who, reminder.from, reminder.what) message = fmt.Sprintf("Hey %s, %s wanted you to be reminded: %s", reminder.who, reminder.from, reminder.what)
} }
p.Bot.SendMessage(reminder.channel, message) p.Bot.Send(bot.Message, reminder.channel, message)
if err := p.deleteReminder(reminder.id); err != nil { if err := p.deleteReminder(reminder.id); err != nil {
log.Print(reminder.id) log.Print(reminder.id)
@ -365,5 +361,3 @@ func reminderer(p *ReminderPlugin) {
p.queueUpNextReminder() p.queueUpNextReminder()
} }
} }
func (p *ReminderPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -14,25 +14,16 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") return makeMessageBy(payload, "tester")
if isCmd {
payload = payload[1:]
}
return msg.Message{
User: &user.User{Name: "tester"},
Channel: "test",
Body: payload,
Command: isCmd,
}
} }
func makeMessageBy(payload, by string) msg.Message { func makeMessageBy(payload, by string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: by}, User: &user.User{Name: by},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -49,7 +40,7 @@ func setup(t *testing.T) (*ReminderPlugin, *bot.MockBot) {
func TestMeReminder(t *testing.T) { func TestMeReminder(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessage("!remind me in 1s don't fail this test")) res := c.message(makeMessage("!remind me in 1s don't fail this test"))
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
assert.True(t, res) assert.True(t, res)
@ -59,7 +50,7 @@ func TestMeReminder(t *testing.T) {
func TestReminder(t *testing.T) { func TestReminder(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessage("!remind testuser in 1s don't fail this test")) res := c.message(makeMessage("!remind testuser in 1s don't fail this test"))
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
assert.True(t, res) assert.True(t, res)
@ -69,9 +60,9 @@ func TestReminder(t *testing.T) {
func TestReminderReorder(t *testing.T) { func TestReminderReorder(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessage("!remind testuser in 2s don't fail this test 2")) res := c.message(makeMessage("!remind testuser in 2s don't fail this test 2"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!remind testuser in 1s don't fail this test 1")) res = c.message(makeMessage("!remind testuser in 1s don't fail this test 1"))
assert.True(t, res) assert.True(t, res)
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
assert.Len(t, mb.Messages, 4) assert.Len(t, mb.Messages, 4)
@ -83,7 +74,7 @@ func TestReminderReorder(t *testing.T) {
func TestReminderParse(t *testing.T) { func TestReminderParse(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessage("!remind testuser in unparseable don't fail this test")) res := c.message(makeMessage("!remind testuser in unparseable don't fail this test"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "Easy cowboy, not sure I can parse that duration.") assert.Contains(t, mb.Messages[0], "Easy cowboy, not sure I can parse that duration.")
@ -91,7 +82,7 @@ func TestReminderParse(t *testing.T) {
func TestEmptyList(t *testing.T) { func TestEmptyList(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessage("!list reminders")) res := c.message(makeMessage("!list reminders"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "no pending reminders") assert.Contains(t, mb.Messages[0], "no pending reminders")
@ -99,11 +90,11 @@ func TestEmptyList(t *testing.T) {
func TestList(t *testing.T) { func TestList(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessage("!remind testuser in 5m don't fail this test 1")) res := c.message(makeMessage("!remind testuser in 5m don't fail this test 1"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!remind testuser in 5m don't fail this test 2")) res = c.message(makeMessage("!remind testuser in 5m don't fail this test 2"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders")) res = c.message(makeMessage("!list reminders"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 3) assert.Len(t, mb.Messages, 3)
assert.Contains(t, mb.Messages[2], "1) tester -> testuser :: don't fail this test 1 @ ") assert.Contains(t, mb.Messages[2], "1) tester -> testuser :: don't fail this test 1 @ ")
@ -112,11 +103,11 @@ func TestList(t *testing.T) {
func TestListBy(t *testing.T) { func TestListBy(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessageBy("!remind testuser in 5m don't fail this test 1", "testuser")) res := c.message(makeMessageBy("!remind testuser in 5m don't fail this test 1", "testuser"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2")) res = c.message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders from testuser")) res = c.message(makeMessage("!list reminders from testuser"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 3) assert.Len(t, mb.Messages, 3)
assert.Contains(t, mb.Messages[2], "don't fail this test 1 @ ") assert.Contains(t, mb.Messages[2], "don't fail this test 1 @ ")
@ -125,11 +116,11 @@ func TestListBy(t *testing.T) {
func TestListTo(t *testing.T) { func TestListTo(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessageBy("!remind testuser2 in 5m don't fail this test 1", "testuser")) res := c.message(makeMessageBy("!remind testuser2 in 5m don't fail this test 1", "testuser"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2")) res = c.message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders to testuser")) res = c.message(makeMessage("!list reminders to testuser"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 3) assert.Len(t, mb.Messages, 3)
assert.NotContains(t, mb.Messages[2], "don't fail this test 1 @ ") assert.NotContains(t, mb.Messages[2], "don't fail this test 1 @ ")
@ -138,11 +129,11 @@ func TestListTo(t *testing.T) {
func TestToEmptyList(t *testing.T) { func TestToEmptyList(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessageBy("!remind testuser2 in 5m don't fail this test 1", "testuser")) res := c.message(makeMessageBy("!remind testuser2 in 5m don't fail this test 1", "testuser"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2")) res = c.message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders to test")) res = c.message(makeMessage("!list reminders to test"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 3) assert.Len(t, mb.Messages, 3)
assert.Contains(t, mb.Messages[2], "no pending reminders") assert.Contains(t, mb.Messages[2], "no pending reminders")
@ -150,11 +141,11 @@ func TestToEmptyList(t *testing.T) {
func TestFromEmptyList(t *testing.T) { func TestFromEmptyList(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
res := c.Message(makeMessageBy("!remind testuser2 in 5m don't fail this test 1", "testuser")) res := c.message(makeMessageBy("!remind testuser2 in 5m don't fail this test 1", "testuser"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2")) res = c.message(makeMessageBy("!remind testuser in 5m don't fail this test 2", "testuser2"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders from test")) res = c.message(makeMessage("!list reminders from test"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 3) assert.Len(t, mb.Messages, 3)
assert.Contains(t, mb.Messages[2], "no pending reminders") assert.Contains(t, mb.Messages[2], "no pending reminders")
@ -164,9 +155,9 @@ func TestBatchMax(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
c.config.Set("Reminder.MaxBatchAdd", "10") c.config.Set("Reminder.MaxBatchAdd", "10")
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!remind testuser every 1h for 24h yikes")) res := c.message(makeMessage("!remind testuser every 1h for 24h yikes"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders")) res = c.message(makeMessage("!list reminders"))
assert.True(t, res) assert.True(t, res)
time.Sleep(6 * time.Second) time.Sleep(6 * time.Second)
assert.Len(t, mb.Messages, 2) assert.Len(t, mb.Messages, 2)
@ -180,11 +171,11 @@ func TestBatchMax(t *testing.T) {
func TestCancel(t *testing.T) { func TestCancel(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!remind testuser in 1m don't fail this test")) res := c.message(makeMessage("!remind testuser in 1m don't fail this test"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!cancel reminder 1")) res = c.message(makeMessage("!cancel reminder 1"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders")) res = c.message(makeMessage("!list reminders"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 3) assert.Len(t, mb.Messages, 3)
assert.Contains(t, mb.Messages[0], "Sure tester, I'll remind testuser.") assert.Contains(t, mb.Messages[0], "Sure tester, I'll remind testuser.")
@ -195,7 +186,7 @@ func TestCancel(t *testing.T) {
func TestCancelMiss(t *testing.T) { func TestCancelMiss(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!cancel reminder 1")) res := c.message(makeMessage("!cancel reminder 1"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "failed to find and cancel reminder: 1") assert.Contains(t, mb.Messages[0], "failed to find and cancel reminder: 1")
@ -208,13 +199,13 @@ func TestLimitList(t *testing.T) {
assert.NotNil(t, c) assert.NotNil(t, c)
//Someone can redo this with a single batch add, but I can't locally due to an old version of sqllite (maybe). //Someone can redo this with a single batch add, but I can't locally due to an old version of sqllite (maybe).
res := c.Message(makeMessage("!remind testuser every 1h for 10h don't fail this test")) res := c.message(makeMessage("!remind testuser every 1h for 10h don't fail this test"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!remind testuser every 1h for 10h don't fail this test")) res = c.message(makeMessage("!remind testuser every 1h for 10h don't fail this test"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!remind testuser every 1h for 10h don't fail this test")) res = c.message(makeMessage("!remind testuser every 1h for 10h don't fail this test"))
assert.True(t, res) assert.True(t, res)
res = c.Message(makeMessage("!list reminders")) res = c.message(makeMessage("!list reminders"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 4) assert.Len(t, mb.Messages, 4)
assert.Contains(t, mb.Messages[0], "Sure tester, I'll remind testuser.") assert.Contains(t, mb.Messages[0], "Sure tester, I'll remind testuser.")
@ -232,22 +223,10 @@ func TestLimitList(t *testing.T) {
func TestHelp(t *testing.T) { func TestHelp(t *testing.T) {
c, mb := setup(t) c, mb := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Help("channel", []string{}) c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBotMessage(t *testing.T) {
c, _ := setup(t)
assert.NotNil(t, c)
assert.False(t, c.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
c, _ := setup(t)
assert.NotNil(t, c)
assert.False(t, c.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
c, _ := setup(t) c, _ := setup(t)
assert.NotNil(t, c) assert.NotNil(t, c)

View File

@ -98,44 +98,38 @@ func (b *board) checkAndMove(dx, dy int) int {
} }
func New(b bot.Bot) *RPGPlugin { func New(b bot.Bot) *RPGPlugin {
return &RPGPlugin{ rpg := &RPGPlugin{
Bot: b, Bot: b,
listenFor: map[string]*board{}, listenFor: map[string]*board{},
} }
b.Register(rpg, bot.Message, rpg.message)
b.Register(rpg, bot.Reply, rpg.replyMessage)
b.Register(rpg, bot.Help, rpg.help)
return rpg
} }
func (p *RPGPlugin) Message(message msg.Message) bool { func (p *RPGPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "start rpg" { if strings.ToLower(message.Body) == "start rpg" {
b := NewRandomBoard() b := NewRandomBoard()
ts := p.Bot.SendMessage(message.Channel, b.toMessageString()) ts, _ := p.Bot.Send(bot.Message, message.Channel, b.toMessageString())
p.listenFor[ts] = b p.listenFor[ts] = b
p.Bot.ReplyToMessageIdentifier(message.Channel, "Over here.", ts) p.Bot.Send(bot.Reply, message.Channel, "Over here.", ts)
return true return true
} }
return false return false
} }
func (p *RPGPlugin) LoadData() { 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.")
} return true
func (p *RPGPlugin) Help(channel string, parts []string) {
p.Bot.SendMessage(channel, "Go find a walkthrough or something.")
}
func (p *RPGPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *RPGPlugin) BotMessage(message msg.Message) bool {
return false
} }
func (p *RPGPlugin) RegisterWeb() *string { func (p *RPGPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *RPGPlugin) ReplyMessage(message msg.Message, identifier string) bool { func (p *RPGPlugin) replyMessage(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 { if b, ok := p.listenFor[identifier]; ok {
@ -155,12 +149,12 @@ func (p *RPGPlugin) ReplyMessage(message msg.Message, identifier string) bool {
switch res { switch res {
case OK: case OK:
p.Bot.Edit(message.Channel, b.toMessageString(), identifier) p.Bot.Send(bot.Edit, message.Channel, b.toMessageString(), identifier)
case WIN: case WIN:
p.Bot.Edit(message.Channel, b.toMessageString(), identifier) p.Bot.Send(bot.Edit, message.Channel, b.toMessageString(), identifier)
p.Bot.ReplyToMessageIdentifier(message.Channel, "congratulations, you beat the easiest level imaginable.", identifier) p.Bot.Send(bot.Reply, message.Channel, "congratulations, you beat the easiest level imaginable.", identifier)
case INVALID: case INVALID:
p.Bot.ReplyToMessageIdentifier(message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier) p.Bot.Send(bot.Reply, message.Channel, fmt.Sprintf("you can't move %s", message.Body), identifier)
} }
return true return true
} }

View File

@ -49,28 +49,31 @@ func (c *cacheItem) getCurrentPage(maxLines int) string {
return page return page
} }
func New(bot bot.Bot) *RSSPlugin { func New(b bot.Bot) *RSSPlugin {
return &RSSPlugin{ rss := &RSSPlugin{
Bot: bot, Bot: b,
cache: map[string]*cacheItem{}, cache: map[string]*cacheItem{},
shelfLife: time.Minute * 20, shelfLife: time.Minute * time.Duration(b.Config().GetInt("rss.shelfLife", 20)),
maxLines: 5, maxLines: b.Config().GetInt("rss.maxLines", 5),
} }
b.Register(rss, bot.Message, rss.message)
b.Register(rss, bot.Help, rss.help)
return rss
} }
func (p *RSSPlugin) Message(message msg.Message) bool { func (p *RSSPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
tokens := strings.Fields(message.Body) tokens := strings.Fields(message.Body)
numTokens := len(tokens) numTokens := len(tokens)
if numTokens == 2 && strings.ToLower(tokens[0]) == "rss" { if numTokens == 2 && strings.ToLower(tokens[0]) == "rss" {
if item, ok := p.cache[strings.ToLower(tokens[1])]; ok && time.Now().Before(item.expiration) { if item, ok := p.cache[strings.ToLower(tokens[1])]; ok && time.Now().Before(item.expiration) {
p.Bot.SendMessage(message.Channel, item.getCurrentPage(p.maxLines)) p.Bot.Send(bot.Message, message.Channel, item.getCurrentPage(p.maxLines))
return true return true
} else { } else {
fp := gofeed.NewParser() fp := gofeed.NewParser()
feed, err := fp.ParseURL(tokens[1]) feed, err := fp.ParseURL(tokens[1])
if err != nil { if err != nil {
p.Bot.SendMessage(message.Channel, fmt.Sprintf("RSS error: %s", err.Error())) p.Bot.Send(bot.Message, message.Channel, fmt.Sprintf("RSS error: %s", err.Error()))
return true return true
} }
item := &cacheItem{ item := &cacheItem{
@ -86,7 +89,7 @@ func (p *RSSPlugin) Message(message msg.Message) bool {
p.cache[strings.ToLower(tokens[1])] = item p.cache[strings.ToLower(tokens[1])] = item
p.Bot.SendMessage(message.Channel, item.getCurrentPage(p.maxLines)) p.Bot.Send(bot.Message, message.Channel, item.getCurrentPage(p.maxLines))
return true return true
} }
} }
@ -94,28 +97,13 @@ func (p *RSSPlugin) Message(message msg.Message) bool {
return false return false
} }
func (p *RSSPlugin) LoadData() {
// This bot has no data to load
}
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *RSSPlugin) Help(channel string, parts []string) { func (p *RSSPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "try '!rss http://rss.cnn.com/rss/edition.rss'") p.Bot.Send(bot.Message, message.Channel, "try '!rss http://rss.cnn.com/rss/edition.rss'")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *RSSPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *RSSPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *RSSPlugin) RegisterWeb() *string { func (p *RSSPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *RSSPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -11,12 +11,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -28,7 +28,7 @@ func TestRSS(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!rss http://rss.cnn.com/rss/edition.rss")) res := c.message(makeMessage("!rss http://rss.cnn.com/rss/edition.rss"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
} }
@ -38,7 +38,7 @@ func TestRSSPaging(t *testing.T) {
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
res := c.Message(makeMessage("!rss http://rss.cnn.com/rss/edition.rss")) res := c.message(makeMessage("!rss http://rss.cnn.com/rss/edition.rss"))
assert.True(t, res) assert.True(t, res)
} }

View File

@ -37,17 +37,17 @@ type game struct {
nextAns int nextAns int
} }
func NewRandomGame(bot bot.Bot, channel, who string) *game { func NewRandomGame(b bot.Bot, channel, who string) *game {
size := rand.Intn(9) + 2 size := rand.Intn(9) + 2
g := game{ g := game{
channel: channel, channel: channel,
bot: bot, bot: b,
who: who, who: who,
start: time.Now(), start: time.Now(),
size: size, size: size,
current: size / 2, current: size / 2,
} }
g.id = bot.SendMessage(channel, g.toMessageString()) g.id, _ = b.Send(bot.Message, channel, g.toMessageString())
g.schedulePush() g.schedulePush()
g.scheduleDecrement() g.scheduleDecrement()
@ -98,11 +98,11 @@ func (g *game) endGame() {
func (g *game) handleDecrement() { func (g *game) handleDecrement() {
g.current++ g.current++
g.bot.Edit(g.channel, g.toMessageString(), g.id) g.bot.Send(bot.Edit, g.channel, g.toMessageString(), g.id)
if g.current > g.size-2 { if g.current > g.size-2 {
g.bot.ReplyToMessageIdentifier(g.channel, "you lose", g.id) g.bot.Send(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)) msg := fmt.Sprintf("%s just lost the game after %s", g.who, time.Now().Sub(g.start))
g.bot.SendMessage(g.channel, msg) g.bot.Send(bot.Message, g.channel, msg)
g.endGame() g.endGame()
} else { } else {
g.scheduleDecrement() g.scheduleDecrement()
@ -110,7 +110,7 @@ func (g *game) handleDecrement() {
} }
func (g *game) handleNotify() { func (g *game) handleNotify() {
g.bot.ReplyToMessageIdentifier(g.channel, "You can push now.\n"+g.generateQuestion(), g.id) g.bot.Send(bot.Reply, g.channel, "You can push now.\n"+g.generateQuestion(), g.id)
} }
func (g *game) generateQuestion() string { func (g *game) generateQuestion() string {
@ -162,39 +162,37 @@ func (g *game) toMessageString() string {
} }
func New(b bot.Bot) *SisyphusPlugin { func New(b bot.Bot) *SisyphusPlugin {
return &SisyphusPlugin{ sp := &SisyphusPlugin{
Bot: b, Bot: b,
listenFor: map[string]*game{}, listenFor: map[string]*game{},
} }
b.Register(sp, bot.Message, sp.message)
b.Register(sp, bot.Reply, sp.replyMessage)
b.Register(sp, bot.Help, sp.help)
return sp
} }
func (p *SisyphusPlugin) Message(message msg.Message) bool { func (p *SisyphusPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "start sisyphus" { if strings.ToLower(message.Body) == "start sisyphus" {
b := NewRandomGame(p.Bot, message.Channel, message.User.Name) b := NewRandomGame(p.Bot, message.Channel, message.User.Name)
p.listenFor[b.id] = b p.listenFor[b.id] = b
p.Bot.ReplyToMessageIdentifier(message.Channel, "Over here.", b.id) p.Bot.Send(bot.Reply, message.Channel, "Over here.", b.id)
return true return true
} }
return false return false
} }
func (p *SisyphusPlugin) Help(channel string, parts []string) { func (p *SisyphusPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "https://en.wikipedia.org/wiki/Sisyphus") p.Bot.Send(bot.Message, message.Channel, "https://en.wikipedia.org/wiki/Sisyphus")
} return true
func (p *SisyphusPlugin) Event(kind string, message msg.Message) bool {
return false
}
func (p *SisyphusPlugin) BotMessage(message msg.Message) bool {
return false
} }
func (p *SisyphusPlugin) RegisterWeb() *string { func (p *SisyphusPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *SisyphusPlugin) ReplyMessage(message msg.Message, identifier string) bool { func (p *SisyphusPlugin) replyMessage(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 { if g, ok := p.listenFor[identifier]; ok {
@ -211,18 +209,18 @@ func (p *SisyphusPlugin) ReplyMessage(message msg.Message, identifier string) bo
if time.Now().After(g.nextPush) { if time.Now().After(g.nextPush) {
if g.checkAnswer(message.Body) { if g.checkAnswer(message.Body) {
p.Bot.Edit(message.Channel, g.toMessageString(), identifier) p.Bot.Send(bot.Edit, message.Channel, g.toMessageString(), identifier)
g.schedulePush() g.schedulePush()
msg := fmt.Sprintf("Ok. You can push again in %s", g.nextPush.Sub(time.Now())) msg := fmt.Sprintf("Ok. You can push again in %s", g.nextPush.Sub(time.Now()))
p.Bot.ReplyToMessageIdentifier(message.Channel, msg, identifier) p.Bot.Send(bot.Reply, message.Channel, msg, identifier)
} else { } else {
p.Bot.ReplyToMessageIdentifier(message.Channel, "you lose", identifier) p.Bot.Send(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)) msg := fmt.Sprintf("%s just lost the sisyphus game after %s", g.who, time.Now().Sub(g.start))
p.Bot.SendMessage(message.Channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
g.endGame() g.endGame()
} }
} else { } else {
p.Bot.ReplyToMessageIdentifier(message.Channel, "you cannot push yet", identifier) p.Bot.Send(bot.Reply, message.Channel, "you cannot push yet", identifier)
} }
return true return true
} }

View File

@ -43,13 +43,16 @@ type TalkerPlugin struct {
sayings []string sayings []string
} }
func New(bot bot.Bot) *TalkerPlugin { func New(b bot.Bot) *TalkerPlugin {
return &TalkerPlugin{ tp := &TalkerPlugin{
Bot: bot, Bot: b,
} }
b.Register(tp, bot.Message, tp.message)
b.Register(tp, bot.Help, tp.help)
return tp
} }
func (p *TalkerPlugin) Message(message msg.Message) bool { func (p *TalkerPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
channel := message.Channel channel := message.Channel
body := message.Body body := message.Body
lowermessage := strings.ToLower(body) lowermessage := strings.ToLower(body)
@ -57,7 +60,7 @@ func (p *TalkerPlugin) Message(message msg.Message) bool {
// TODO: This ought to be space split afterwards to remove any punctuation // TODO: This ought to be space split afterwards to remove any punctuation
if message.Command && strings.HasPrefix(lowermessage, "say") { if message.Command && strings.HasPrefix(lowermessage, "say") {
msg := strings.TrimSpace(body[3:]) msg := strings.TrimSpace(body[3:])
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, channel, msg)
return true return true
} }
@ -73,30 +76,19 @@ func (p *TalkerPlugin) Message(message msg.Message) bool {
line = strings.Replace(line, "{nick}", nick, 1) line = strings.Replace(line, "{nick}", nick, 1)
output += line + "\n" output += line + "\n"
} }
p.Bot.SendMessage(channel, output) p.Bot.Send(bot.Message, channel, output)
return true return true
} }
return false return false
} }
func (p *TalkerPlugin) Help(channel string, parts []string) { func (p *TalkerPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.Bot.SendMessage(channel, "Hi, this is talker. I like to talk about FredFelps!") p.Bot.Send(bot.Message, message.Channel, "Hi, this is talker. I like to talk about FredFelps!")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *TalkerPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *TalkerPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *TalkerPlugin) RegisterWeb() *string { func (p *TalkerPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *TalkerPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -29,7 +29,7 @@ func TestGoatse(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("goatse")) res := c.message(makeMessage("goatse"))
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
assert.False(t, res) assert.False(t, res)
} }
@ -38,7 +38,7 @@ func TestGoatseCommand(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!goatse")) res := c.message(makeMessage("!goatse"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "g o a t s e") assert.Contains(t, mb.Messages[0], "g o a t s e")
@ -48,7 +48,7 @@ func TestGoatseWithNickCommand(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!goatse seabass")) res := c.message(makeMessage("!goatse seabass"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "g o a t s e") assert.Contains(t, mb.Messages[0], "g o a t s e")
@ -59,7 +59,7 @@ func TestSay(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("say hello")) res := c.message(makeMessage("say hello"))
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
assert.False(t, res) assert.False(t, res)
} }
@ -68,7 +68,7 @@ func TestSayCommand(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
res := c.Message(makeMessage("!say hello")) res := c.message(makeMessage("!say hello"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.True(t, res) assert.True(t, res)
assert.Contains(t, mb.Messages[0], "hello") assert.Contains(t, mb.Messages[0], "hello")
@ -78,24 +78,10 @@ func TestHelp(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
assert.NotNil(t, c) assert.NotNil(t, c)
c.Help("channel", []string{}) c.help(bot.Help, msg.Message{Channel: "channel"}, []string{})
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
} }
func TestBotMessage(t *testing.T) {
mb := bot.NewMockBot()
c := New(mb)
assert.NotNil(t, c)
assert.False(t, c.BotMessage(makeMessage("test")))
}
func TestEvent(t *testing.T) {
mb := bot.NewMockBot()
c := New(mb)
assert.NotNil(t, c)
assert.False(t, c.Event("dummy", makeMessage("test")))
}
func TestRegisterWeb(t *testing.T) { func TestRegisterWeb(t *testing.T) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)

View File

@ -16,23 +16,25 @@ type TellPlugin struct {
} }
func New(b bot.Bot) *TellPlugin { func New(b bot.Bot) *TellPlugin {
return &TellPlugin{b, make(map[string][]string)} tp := &TellPlugin{b, make(map[string][]string)}
b.Register(tp, bot.Message, tp.message)
return tp
} }
func (t *TellPlugin) Message(message msg.Message) bool { func (t *TellPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.HasPrefix(strings.ToLower(message.Body), "tell") { if strings.HasPrefix(strings.ToLower(message.Body), "tell") {
parts := strings.Split(message.Body, " ") parts := strings.Split(message.Body, " ")
target := strings.ToLower(parts[1]) target := strings.ToLower(parts[1])
newMessage := strings.Join(parts[2:], " ") newMessage := strings.Join(parts[2:], " ")
newMessage = fmt.Sprintf("Hey, %s. %s said: %s", target, message.User.Name, newMessage) newMessage = fmt.Sprintf("Hey, %s. %s said: %s", target, message.User.Name, newMessage)
t.users[target] = append(t.users[target], newMessage) t.users[target] = append(t.users[target], newMessage)
t.b.SendMessage(message.Channel, fmt.Sprintf("Okay. I'll tell %s.", target)) t.b.Send(bot.Message, message.Channel, fmt.Sprintf("Okay. I'll tell %s.", target))
return true return true
} }
uname := strings.ToLower(message.User.Name) uname := strings.ToLower(message.User.Name)
if msg, ok := t.users[uname]; ok && len(msg) > 0 { if msg, ok := t.users[uname]; ok && len(msg) > 0 {
for _, m := range msg { for _, m := range msg {
t.b.SendMessage(message.Channel, string(m)) t.b.Send(bot.Message, message.Channel, string(m))
} }
t.users[uname] = []string{} t.users[uname] = []string{}
return true return true
@ -40,8 +42,4 @@ func (t *TellPlugin) Message(message msg.Message) bool {
return false return false
} }
func (t *TellPlugin) Event(kind string, message msg.Message) bool { return false }
func (t *TellPlugin) ReplyMessage(msg.Message, string) bool { return false }
func (t *TellPlugin) BotMessage(message msg.Message) bool { return false }
func (t *TellPlugin) Help(channel string, parts []string) {}
func (t *TellPlugin) RegisterWeb() *string { return nil } func (t *TellPlugin) RegisterWeb() *string { return nil }

View File

@ -51,10 +51,10 @@ type stream struct {
} `json:"pagination"` } `json:"pagination"`
} }
func New(bot bot.Bot) *TwitchPlugin { func New(b bot.Bot) *TwitchPlugin {
p := &TwitchPlugin{ p := &TwitchPlugin{
Bot: bot, Bot: b,
config: bot.Config(), config: b.Config(),
twitchList: map[string]*Twitcher{}, twitchList: map[string]*Twitcher{},
} }
@ -70,13 +70,10 @@ func New(bot bot.Bot) *TwitchPlugin {
go p.twitchLoop(ch) go p.twitchLoop(ch)
} }
b.Register(p, bot.Message, p.message)
return p return p
} }
func (p *TwitchPlugin) BotMessage(message msg.Message) bool {
return false
}
func (p *TwitchPlugin) RegisterWeb() *string { func (p *TwitchPlugin) RegisterWeb() *string {
http.HandleFunc("/isstreaming/", p.serveStreaming) http.HandleFunc("/isstreaming/", p.serveStreaming)
tmp := "/isstreaming" tmp := "/isstreaming"
@ -114,7 +111,7 @@ func (p *TwitchPlugin) serveStreaming(w http.ResponseWriter, r *http.Request) {
} }
} }
func (p *TwitchPlugin) Message(message msg.Message) bool { func (p *TwitchPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
if strings.ToLower(message.Body) == "twitch status" { if strings.ToLower(message.Body) == "twitch status" {
channel := message.Channel channel := message.Channel
if users := p.config.GetArray("Twitch."+channel+".Users", []string{}); len(users) > 0 { if users := p.config.GetArray("Twitch."+channel+".Users", []string{}); len(users) > 0 {
@ -130,17 +127,10 @@ func (p *TwitchPlugin) Message(message msg.Message) bool {
return false return false
} }
func (p *TwitchPlugin) Event(kind string, message msg.Message) bool { func (p *TwitchPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
return false
}
func (p *TwitchPlugin) LoadData() {
}
func (p *TwitchPlugin) Help(channel string, parts []string) {
msg := "There's no help for you here." msg := "There's no help for you here."
p.Bot.SendMessage(channel, msg) p.Bot.Send(bot.Message, message.Channel, msg)
return true
} }
func (p *TwitchPlugin) twitchLoop(channel string) { func (p *TwitchPlugin) twitchLoop(channel string) {
@ -224,21 +214,19 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri
streamWord := p.config.Get("Twitch.StreamWord", "streaming") streamWord := p.config.Get("Twitch.StreamWord", "streaming")
if alwaysPrintStatus { if alwaysPrintStatus {
if game == "" { if game == "" {
p.Bot.SendMessage(channel, fmt.Sprintf("%s is not %s.", twitcher.name, streamWord)) p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s is not %s.", twitcher.name, streamWord))
} else { } else {
p.Bot.SendMessage(channel, fmt.Sprintf("%s is %s %s at %s", twitcher.name, streamWord, game, twitcher.URL())) p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s is %s %s at %s", twitcher.name, streamWord, game, twitcher.URL()))
} }
} else if game == "" { } else if game == "" {
if twitcher.game != "" { if twitcher.game != "" {
p.Bot.SendMessage(channel, fmt.Sprintf("%s just stopped %s.", twitcher.name, streamWord)) p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s just stopped %s.", twitcher.name, streamWord))
} }
twitcher.game = "" twitcher.game = ""
} else { } else {
if twitcher.game != game { if twitcher.game != game {
p.Bot.SendMessage(channel, fmt.Sprintf("%s is %s %s at %s", twitcher.name, streamWord, game, twitcher.URL())) p.Bot.Send(bot.Message, channel, fmt.Sprintf("%s is %s %s at %s", twitcher.name, streamWord, game, twitcher.URL()))
} }
twitcher.game = game twitcher.game = game
} }
} }
func (p *TwitchPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -44,6 +44,6 @@ func makeTwitchPlugin(t *testing.T) (*TwitchPlugin, *bot.MockBot) {
func TestTwitch(t *testing.T) { func TestTwitch(t *testing.T) {
b, mb := makeTwitchPlugin(t) b, mb := makeTwitchPlugin(t)
b.Message(makeMessage("!twitch status")) b.message(makeMessage("!twitch status"))
assert.NotEmpty(t, mb.Messages) assert.NotEmpty(t, mb.Messages)
} }

View File

@ -17,17 +17,20 @@ type YourPlugin struct {
} }
// NewYourPlugin creates a new YourPlugin with the Plugin interface // NewYourPlugin creates a new YourPlugin with the Plugin interface
func New(bot bot.Bot) *YourPlugin { func New(b bot.Bot) *YourPlugin {
return &YourPlugin{ yp := &YourPlugin{
bot: bot, bot: b,
config: bot.Config(), config: b.Config(),
} }
b.Register(yp, bot.Message, yp.message)
b.Register(yp, bot.Help, yp.help)
return yp
} }
// Message responds to the bot hook on recieving messages. // 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. // 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. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *YourPlugin) Message(message msg.Message) bool { func (p *YourPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
maxLen := p.config.GetInt("your.maxlength", 140) maxLen := p.config.GetInt("your.maxlength", 140)
if len(message.Body) > maxLen { if len(message.Body) > maxLen {
return false return false
@ -43,30 +46,19 @@ func (p *YourPlugin) Message(message msg.Message) bool {
} }
} }
if msg != message.Body { if msg != message.Body {
p.bot.SendMessage(message.Channel, msg) p.bot.Send(bot.Message, message.Channel, msg)
return true return true
} }
return false return false
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.
func (p *YourPlugin) Help(channel string, parts []string) { func (p *YourPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.SendMessage(channel, "Your corrects people's grammar.") p.bot.Send(bot.Message, message.Channel, "Your corrects people's grammar.")
} return true
// Empty event handler because this plugin does not do anything on event recv
func (p *YourPlugin) Event(kind string, message msg.Message) bool {
return false
}
// Handler for bot's own messages
func (p *YourPlugin) BotMessage(message msg.Message) bool {
return false
} }
// Register any web URLs desired // Register any web URLs desired
func (p *YourPlugin) RegisterWeb() *string { func (p *YourPlugin) RegisterWeb() *string {
return nil return nil
} }
func (p *YourPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -12,12 +12,12 @@ import (
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
) )
func makeMessage(payload string) msg.Message { func makeMessage(payload string) (bot.Kind, msg.Message) {
isCmd := strings.HasPrefix(payload, "!") isCmd := strings.HasPrefix(payload, "!")
if isCmd { if isCmd {
payload = payload[1:] payload = payload[1:]
} }
return msg.Message{ return bot.Message, msg.Message{
User: &user.User{Name: "tester"}, User: &user.User{Name: "tester"},
Channel: "test", Channel: "test",
Body: payload, Body: payload,
@ -39,7 +39,7 @@ func TestReplacement(t *testing.T) {
c.config.Set("your.replacements.0.freq", "1.0") c.config.Set("your.replacements.0.freq", "1.0")
c.config.Set("your.replacements.0.this", "fuck") c.config.Set("your.replacements.0.this", "fuck")
c.config.Set("your.replacements.0.that", "duck") c.config.Set("your.replacements.0.that", "duck")
res := c.Message(makeMessage("fuck a duck")) res := c.message(makeMessage("fuck a duck"))
assert.True(t, res) assert.True(t, res)
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "duck a duck") assert.Contains(t, mb.Messages[0], "duck a duck")
@ -60,6 +60,6 @@ func TestNoReplacement(t *testing.T) {
c.config.Set("your.replacements.2.freq", "1.0") c.config.Set("your.replacements.2.freq", "1.0")
c.config.Set("your.replacements.2.this", "Fuck") c.config.Set("your.replacements.2.this", "Fuck")
c.config.Set("your.replacements.2.that", "duck") c.config.Set("your.replacements.2.that", "duck")
c.Message(makeMessage("fuck a duck")) c.message(makeMessage("fuck a duck"))
assert.Len(t, mb.Messages, 0) assert.Len(t, mb.Messages, 0)
} }

View File

@ -26,11 +26,14 @@ type ZorkPlugin struct {
zorks map[string]io.WriteCloser zorks map[string]io.WriteCloser
} }
func New(b bot.Bot) bot.Handler { func New(b bot.Bot) bot.Plugin {
return &ZorkPlugin{ z := &ZorkPlugin{
bot: b, bot: b,
zorks: make(map[string]io.WriteCloser), zorks: make(map[string]io.WriteCloser),
} }
b.Register(z, bot.Message, z.message)
b.Register(z, bot.Help, z.help)
return z
} }
func (p *ZorkPlugin) runZork(ch string) error { func (p *ZorkPlugin) runZork(ch string) error {
@ -75,7 +78,7 @@ func (p *ZorkPlugin) runZork(ch string) error {
m := strings.Replace(s.Text(), ">", "", -1) m := strings.Replace(s.Text(), ">", "", -1)
m = strings.Replace(m, "\n", "\n>", -1) m = strings.Replace(m, "\n", "\n>", -1)
m = ">" + m + "\n" m = ">" + m + "\n"
p.bot.SendMessage(ch, m) p.bot.Send(bot.Message, ch, m)
} }
}() }()
go func() { go func() {
@ -91,7 +94,7 @@ func (p *ZorkPlugin) runZork(ch string) error {
return nil return nil
} }
func (p *ZorkPlugin) Message(message msg.Message) bool { func (p *ZorkPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
m := strings.ToLower(message.Body) m := strings.ToLower(message.Body)
log.Printf("got message [%s]\n", m) log.Printf("got message [%s]\n", m)
if ts := strings.Fields(m); len(ts) < 1 || ts[0] != "zork" { if ts := strings.Fields(m); len(ts) < 1 || ts[0] != "zork" {
@ -104,7 +107,7 @@ func (p *ZorkPlugin) Message(message msg.Message) bool {
defer p.Unlock() defer p.Unlock()
if p.zorks[ch] == nil { if p.zorks[ch] == nil {
if err := p.runZork(ch); err != nil { if err := p.runZork(ch); err != nil {
p.bot.SendMessage(ch, "failed to run zork: "+err.Error()) p.bot.Send(bot.Message, ch, "failed to run zork: "+err.Error())
return true return true
} }
} }
@ -113,14 +116,9 @@ func (p *ZorkPlugin) Message(message msg.Message) bool {
return true return true
} }
func (p *ZorkPlugin) Event(_ string, _ msg.Message) bool { return false } func (p *ZorkPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
p.bot.Send(bot.Message, message.Channel, "Play zork using 'zork <zork command>'.")
func (p *ZorkPlugin) BotMessage(_ msg.Message) bool { return false } return true
func (p *ZorkPlugin) Help(ch string, _ []string) {
p.bot.SendMessage(ch, "Play zork using 'zork <zork command>'.")
} }
func (p *ZorkPlugin) RegisterWeb() *string { return nil } func (p *ZorkPlugin) RegisterWeb() *string { return nil }
func (p *ZorkPlugin) ReplyMessage(message msg.Message, identifier string) bool { return false }

View File

@ -44,9 +44,7 @@ type Slack struct {
emoji map[string]string emoji map[string]string
eventReceived func(msg.Message) event func(bot.Kind, msg.Message, ...interface{})
messageReceived func(msg.Message)
replyMessageReceived func(msg.Message, string)
} }
var idCounter uint64 var idCounter uint64
@ -177,7 +175,31 @@ func New(c *config.Config) *Slack {
} }
} }
func checkReturnStatus(response *http.Response) bool { func (s *Slack) Send(kind bot.Kind, args ...interface{}) (string, error) {
switch kind {
case bot.Message:
return s.sendMessage(args[0].(string), args[1].(string))
case bot.Action:
return s.sendAction(args[0].(string), args[1].(string))
case bot.Edit:
return s.edit(args[0].(string), args[1].(string), args[2].(string))
case bot.Reply:
switch args[2].(type) {
case msg.Message:
return s.replyToMessage(args[0].(string), args[1].(string), args[2].(msg.Message))
case string:
return s.replyToMessageIdentifier(args[0].(string), args[1].(string), args[2].(string))
default:
return "", fmt.Errorf("Invalid types given to Reply")
}
case bot.Reaction:
return s.react(args[0].(string), args[1].(string), args[2].(msg.Message))
default:
}
return "", fmt.Errorf("No handler for message type %d", kind)
}
func checkReturnStatus(response *http.Response) error {
type Response struct { type Response struct {
OK bool `json:"ok"` OK bool `json:"ok"`
} }
@ -185,32 +207,24 @@ func checkReturnStatus(response *http.Response) bool {
body, err := ioutil.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
response.Body.Close() response.Body.Close()
if err != nil { if err != nil {
log.Printf("Error reading Slack API body: %s", err) err := fmt.Errorf("Error reading Slack API body: %s", err)
return false return err
} }
var resp Response var resp Response
err = json.Unmarshal(body, &resp) err = json.Unmarshal(body, &resp)
if err != nil { if err != nil {
log.Printf("Error parsing message response: %s", err) err := fmt.Errorf("Error parsing message response: %s", err)
return false return err
} }
return resp.OK return nil
} }
func (s *Slack) RegisterEventReceived(f func(msg.Message)) { func (s *Slack) RegisterEvent(f func(bot.Kind, msg.Message, ...interface{})) {
s.eventReceived = f s.event = f
} }
func (s *Slack) RegisterMessageReceived(f func(msg.Message)) { func (s *Slack) sendMessageType(channel, message string, meMessage bool) (string, error) {
s.messageReceived = f
}
func (s *Slack) RegisterReplyMessageReceived(f func(msg.Message, string)) {
s.replyMessageReceived = f
}
func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string, error) {
postUrl := "https://slack.com/api/chat.postMessage" postUrl := "https://slack.com/api/chat.postMessage"
if meMessage { if meMessage {
postUrl = "https://slack.com/api/chat.meMessage" postUrl = "https://slack.com/api/chat.meMessage"
@ -262,19 +276,19 @@ func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string
return mr.Timestamp, err return mr.Timestamp, err
} }
func (s *Slack) SendMessage(channel, message string) string { func (s *Slack) sendMessage(channel, message string) (string, error) {
log.Printf("Sending message to %s: %s", channel, message) log.Printf("Sending message to %s: %s", channel, message)
identifier, _ := s.SendMessageType(channel, message, false) identifier, err := s.sendMessageType(channel, message, false)
return identifier return identifier, err
} }
func (s *Slack) SendAction(channel, message string) string { func (s *Slack) sendAction(channel, message string) (string, error) {
log.Printf("Sending action to %s: %s", channel, message) log.Printf("Sending action to %s: %s", channel, message)
identifier, _ := s.SendMessageType(channel, "_"+message+"_", true) identifier, err := s.sendMessageType(channel, "_"+message+"_", true)
return identifier return identifier, err
} }
func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { func (s *Slack) replyToMessageIdentifier(channel, message, identifier string) (string, error) {
nick := s.config.Get("Nick", "bot") nick := s.config.Get("Nick", "bot")
icon := s.config.Get("IconURL", "https://placekitten.com/128/128") icon := s.config.Get("IconURL", "https://placekitten.com/128/128")
@ -288,15 +302,15 @@ func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (s
}) })
if err != nil { if err != nil {
log.Printf("Error sending Slack reply: %s", err) err := fmt.Errorf("Error sending Slack reply: %s", err)
return "", false return "", err
} }
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close() resp.Body.Close()
if err != nil { if err != nil {
log.Printf("Error reading Slack API body: %s", err) err := fmt.Errorf("Error reading Slack API body: %s", err)
return "", false return "", err
} }
log.Println(string(body)) log.Println(string(body))
@ -309,22 +323,22 @@ func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (s
var mr MessageResponse var mr MessageResponse
err = json.Unmarshal(body, &mr) err = json.Unmarshal(body, &mr)
if err != nil { if err != nil {
log.Printf("Error parsing message response: %s", err) err := fmt.Errorf("Error parsing message response: %s", err)
return "", false return "", err
} }
if !mr.OK { if !mr.OK {
return "", false return "", fmt.Errorf("Got !OK from slack message response")
} }
return mr.Timestamp, err == nil return mr.Timestamp, err
} }
func (s *Slack) ReplyToMessage(channel, message string, replyTo msg.Message) (string, bool) { func (s *Slack) replyToMessage(channel, message string, replyTo msg.Message) (string, error) {
return s.ReplyToMessageIdentifier(channel, message, replyTo.AdditionalData["RAW_SLACK_TIMESTAMP"]) return s.replyToMessageIdentifier(channel, message, replyTo.AdditionalData["RAW_SLACK_TIMESTAMP"])
} }
func (s *Slack) React(channel, reaction string, message msg.Message) bool { func (s *Slack) react(channel, reaction string, message msg.Message) (string, error) {
log.Printf("Reacting in %s: %s", channel, reaction) log.Printf("Reacting in %s: %s", channel, reaction)
resp, err := http.PostForm("https://slack.com/api/reactions.add", resp, err := http.PostForm("https://slack.com/api/reactions.add",
url.Values{"token": {s.token}, url.Values{"token": {s.token},
@ -332,13 +346,13 @@ func (s *Slack) React(channel, reaction string, message msg.Message) bool {
"channel": {channel}, "channel": {channel},
"timestamp": {message.AdditionalData["RAW_SLACK_TIMESTAMP"]}}) "timestamp": {message.AdditionalData["RAW_SLACK_TIMESTAMP"]}})
if err != nil { if err != nil {
log.Printf("reaction failed: %s", err) err := fmt.Errorf("reaction failed: %s", err)
return false return "", err
} }
return checkReturnStatus(resp) return "", checkReturnStatus(resp)
} }
func (s *Slack) Edit(channel, newMessage, identifier string) bool { func (s *Slack) edit(channel, newMessage, identifier string) (string, error) {
log.Printf("Editing in (%s) %s: %s", identifier, channel, newMessage) log.Printf("Editing in (%s) %s: %s", identifier, channel, newMessage)
resp, err := http.PostForm("https://slack.com/api/chat.update", resp, err := http.PostForm("https://slack.com/api/chat.update",
url.Values{"token": {s.token}, url.Values{"token": {s.token},
@ -346,10 +360,10 @@ func (s *Slack) Edit(channel, newMessage, identifier string) bool {
"text": {newMessage}, "text": {newMessage},
"ts": {identifier}}) "ts": {identifier}})
if err != nil { if err != nil {
log.Printf("edit failed: %s", err) err := fmt.Errorf("edit failed: %s", err)
return false return "", err
} }
return checkReturnStatus(resp) return "", checkReturnStatus(resp)
} }
func (s *Slack) GetEmojiList() map[string]string { func (s *Slack) GetEmojiList() map[string]string {
@ -441,11 +455,11 @@ func (s *Slack) Serve() error {
log.Printf("Ignoring message: %+v\nlastRecieved: %v msg: %v", msg.ID, s.lastRecieved, m.Time) log.Printf("Ignoring message: %+v\nlastRecieved: %v msg: %v", msg.ID, s.lastRecieved, m.Time)
} else { } else {
s.lastRecieved = m.Time s.lastRecieved = m.Time
s.messageReceived(m) s.event(bot.Message, m)
} }
} else if msg.ThreadTs != "" { } else if msg.ThreadTs != "" {
//we're throwing away some information here by not parsing the correct reply object type, but that's okay //we're throwing away some information here by not parsing the correct reply object type, but that's okay
s.replyMessageReceived(s.buildLightReplyMessage(msg), msg.ThreadTs) s.event(bot.Reply, s.buildLightReplyMessage(msg), msg.ThreadTs)
} else { } else {
log.Printf("THAT MESSAGE WAS HIDDEN: %+v", msg.ID) log.Printf("THAT MESSAGE WAS HIDDEN: %+v", msg.ID)
} }