mirror of https://github.com/velour/catbase.git
parent
5ded7a8f7b
commit
9600e0dc63
|
@ -46,6 +46,9 @@ type bot struct {
|
||||||
|
|
||||||
// The entries to the bot's HTTP interface
|
// The entries to the bot's HTTP interface
|
||||||
httpEndPoints map[string]string
|
httpEndPoints map[string]string
|
||||||
|
|
||||||
|
// filters registered by plugins
|
||||||
|
filters map[string]func(string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
|
@ -77,6 +80,7 @@ func New(config *config.Config, connector Connector) Bot {
|
||||||
logOut: logOut,
|
logOut: logOut,
|
||||||
version: config.Version,
|
version: config.Version,
|
||||||
httpEndPoints: make(map[string]string),
|
httpEndPoints: make(map[string]string),
|
||||||
|
filters: make(map[string]func(string) string),
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.migrateDB()
|
bot.migrateDB()
|
||||||
|
@ -267,3 +271,8 @@ func (b *bot) checkAdmin(nick string) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register a text filter which every outgoing message is passed through
|
||||||
|
func (b *bot) RegisterFilter(name string, f func(string) string) {
|
||||||
|
b.filters[name] = f
|
||||||
|
}
|
||||||
|
|
|
@ -149,6 +149,10 @@ func (b *bot) Filter(message msg.Message, input string) string {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, f := range b.filters {
|
||||||
|
input = f(input)
|
||||||
|
}
|
||||||
|
|
||||||
varname := r.FindString(input)
|
varname := r.FindString(input)
|
||||||
blacklist := make(map[string]bool)
|
blacklist := make(map[string]bool)
|
||||||
blacklist["$and"] = true
|
blacklist["$and"] = true
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Bot interface {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connector interface {
|
type Connector interface {
|
||||||
|
|
|
@ -41,6 +41,7 @@ func (mb *MockBot) CheckAdmin(nick string) bool { return false }
|
||||||
|
|
||||||
func (mb *MockBot) React(channel, reaction string, message msg.Message) {}
|
func (mb *MockBot) React(channel, reaction string, message msg.Message) {}
|
||||||
func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) }
|
func (mb *MockBot) GetEmojiList() map[string]string { return make(map[string]string) }
|
||||||
|
func (mb *MockBot) RegisterFilter(s string, f func(string) string) {}
|
||||||
|
|
||||||
func NewMockBot() *MockBot {
|
func NewMockBot() *MockBot {
|
||||||
db, err := sqlx.Open("sqlite3_custom", ":memory:")
|
db, err := sqlx.Open("sqlite3_custom", ":memory:")
|
||||||
|
|
|
@ -100,6 +100,9 @@ type Config struct {
|
||||||
PositiveReactions []string
|
PositiveReactions []string
|
||||||
NegativeReactions []string
|
NegativeReactions []string
|
||||||
}
|
}
|
||||||
|
Inventory struct {
|
||||||
|
Max int
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
2
main.go
2
main.go
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/velour/catbase/plugins/emojifyme"
|
"github.com/velour/catbase/plugins/emojifyme"
|
||||||
"github.com/velour/catbase/plugins/fact"
|
"github.com/velour/catbase/plugins/fact"
|
||||||
"github.com/velour/catbase/plugins/first"
|
"github.com/velour/catbase/plugins/first"
|
||||||
|
"github.com/velour/catbase/plugins/inventory"
|
||||||
"github.com/velour/catbase/plugins/leftpad"
|
"github.com/velour/catbase/plugins/leftpad"
|
||||||
"github.com/velour/catbase/plugins/reaction"
|
"github.com/velour/catbase/plugins/reaction"
|
||||||
"github.com/velour/catbase/plugins/reminder"
|
"github.com/velour/catbase/plugins/reminder"
|
||||||
|
@ -67,6 +68,7 @@ func main() {
|
||||||
b.AddHandler("reaction", reaction.New(b))
|
b.AddHandler("reaction", reaction.New(b))
|
||||||
b.AddHandler("emojifyme", emojifyme.New(b))
|
b.AddHandler("emojifyme", emojifyme.New(b))
|
||||||
b.AddHandler("twitch", twitch.New(b))
|
b.AddHandler("twitch", twitch.New(b))
|
||||||
|
b.AddHandler("inventory", inventory.New(b))
|
||||||
// catches anything left, will always return true
|
// catches anything left, will always return true
|
||||||
b.AddHandler("factoid", fact.New(b))
|
b.AddHandler("factoid", fact.New(b))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
// © 2016 the CatBase Authors under the WTFPL license. See AUTHORS for the list of authors.
|
||||||
|
|
||||||
|
// Package inventory contains the plugin that allows the bot to pad messages
|
||||||
|
// See the bucket RFC inventory: http://wiki.xkcd.com/irc/Bucket_inventory
|
||||||
|
package inventory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/velour/catbase/bot"
|
||||||
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
"github.com/velour/catbase/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InventoryPlugin struct {
|
||||||
|
*sqlx.DB
|
||||||
|
bot bot.Bot
|
||||||
|
config *config.Config
|
||||||
|
r1, r2, r3, r4, r5 *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new InventoryPlugin with the Plugin interface
|
||||||
|
func New(bot bot.Bot) *InventoryPlugin {
|
||||||
|
config := bot.Config()
|
||||||
|
r1, err := regexp.Compile("take this (.+)")
|
||||||
|
checkerr(err)
|
||||||
|
r2, err := regexp.Compile("have a (.+)")
|
||||||
|
checkerr(err)
|
||||||
|
r3, err := regexp.Compile(fmt.Sprintf("puts (.+) in %s([^a-zA-Z].*)?", config.Nick))
|
||||||
|
checkerr(err)
|
||||||
|
r4, err := regexp.Compile(fmt.Sprintf("gives %s (.+)", config.Nick))
|
||||||
|
checkerr(err)
|
||||||
|
r5, err := regexp.Compile(fmt.Sprintf("gives (.+) to %s([^a-zA-Z].*)?", config.Nick))
|
||||||
|
checkerr(err)
|
||||||
|
|
||||||
|
p := InventoryPlugin{
|
||||||
|
DB: bot.DB(),
|
||||||
|
bot: bot,
|
||||||
|
config: config,
|
||||||
|
r1: r1, r2: r2, r3: r3, r4: r4, r5: r5,
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.RegisterFilter("$item", p.itemFilter)
|
||||||
|
bot.RegisterFilter("$giveitem", p.giveItemFilter)
|
||||||
|
|
||||||
|
_, err = p.DB.Exec(`create table if not exists inventory (
|
||||||
|
item string primary key
|
||||||
|
);`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) giveItemFilter(input string) string {
|
||||||
|
for strings.Contains(input, "$giveitem") {
|
||||||
|
item := p.random()
|
||||||
|
input = strings.Replace(input, "$giveitem", item, 1)
|
||||||
|
p.remove(item)
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) itemFilter(input string) string {
|
||||||
|
for strings.Contains(input, "$item") {
|
||||||
|
input = strings.Replace(input, "$item", p.random(), 1)
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) Message(message msg.Message) bool {
|
||||||
|
m := message.Body
|
||||||
|
log.Printf("inventory trying to read %+v", message)
|
||||||
|
if message.Command {
|
||||||
|
if strings.ToLower(m) == "inventory" {
|
||||||
|
items := p.getAll()
|
||||||
|
say := "I'm not holding anything"
|
||||||
|
if len(items) > 0 {
|
||||||
|
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, ", "))
|
||||||
|
}
|
||||||
|
p.bot.SendMessage(message.Channel, say)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Randall> Bucket[:,] take this (.+)
|
||||||
|
// <Randall> Bucket[:,] have a (.+)
|
||||||
|
if matches := p.r1.FindStringSubmatch(m); len(matches) > 0 {
|
||||||
|
log.Printf("Found item to add: %s", matches[1])
|
||||||
|
return p.addItem(message, matches[1])
|
||||||
|
}
|
||||||
|
if matches := p.r2.FindStringSubmatch(m); len(matches) > 0 {
|
||||||
|
log.Printf("Found item to add: %s", matches[1])
|
||||||
|
return p.addItem(message, matches[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if message.Action {
|
||||||
|
log.Println("Inventory found an action")
|
||||||
|
// * Randall puts (.+) in Bucket([^a-zA-Z].*)?
|
||||||
|
// * Randall gives Bucket (.+)
|
||||||
|
// * Randall gives (.+) to Bucket([^a-zA-Z].*)?
|
||||||
|
|
||||||
|
if matches := p.r3.FindStringSubmatch(m); len(matches) > 0 {
|
||||||
|
log.Printf("Found item to add: %s", matches[1])
|
||||||
|
return p.addItem(message, matches[1])
|
||||||
|
}
|
||||||
|
if matches := p.r4.FindStringSubmatch(m); len(matches) > 0 {
|
||||||
|
log.Printf("Found item to add: %s", matches[1])
|
||||||
|
return p.addItem(message, matches[1])
|
||||||
|
}
|
||||||
|
if matches := p.r5.FindStringSubmatch(m); len(matches) > 0 {
|
||||||
|
log.Printf("Found item to add: %s", matches[1])
|
||||||
|
return p.addItem(message, matches[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) removeRandom() string {
|
||||||
|
var name string
|
||||||
|
err := p.QueryRow(`select item from inventory order by random() limit 1`).Scan(
|
||||||
|
&name,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error finding random entry: %s", err)
|
||||||
|
return "IAMERROR"
|
||||||
|
}
|
||||||
|
_, err = p.Exec(`delete from inventory where item=?`, name)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error finding random entry: %s", err)
|
||||||
|
return "IAMERROR"
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) count() int {
|
||||||
|
var output int
|
||||||
|
err := p.QueryRow(`select count(*) as count from inventory`).Scan(&output)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error checking for item: %s", err)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) random() string {
|
||||||
|
var name string
|
||||||
|
err := p.QueryRow(`select item from inventory order by random() limit 1`).Scan(
|
||||||
|
&name,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error finding random entry: %s", err)
|
||||||
|
return "IAMERROR"
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) getAll() []string {
|
||||||
|
rows, err := p.Queryx(`select item from inventory`)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting all items: %s", err)
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
output := []string{}
|
||||||
|
for rows.Next() {
|
||||||
|
var item string
|
||||||
|
rows.Scan(&item)
|
||||||
|
output = append(output, item)
|
||||||
|
}
|
||||||
|
rows.Close()
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) exists(i string) bool {
|
||||||
|
var output int
|
||||||
|
err := p.QueryRow(`select count(*) as count from inventory where item=?`, i).Scan(&output)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error checking for item: %s", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return output > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) remove(i string) {
|
||||||
|
_, err := p.Exec(`delete from inventory where item=?`, i)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error inserting new inventory item: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
|
||||||
|
if p.exists(i) {
|
||||||
|
p.bot.SendMessage(m.Channel, fmt.Sprintf("I already have %s.", i))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
var removed string
|
||||||
|
if p.count() > p.config.Inventory.Max {
|
||||||
|
removed = p.removeRandom()
|
||||||
|
}
|
||||||
|
_, err := p.Exec(`INSERT INTO inventory (item) values (?)`, i)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error inserting new inventory item: %s", err)
|
||||||
|
}
|
||||||
|
if removed != "" {
|
||||||
|
p.bot.SendAction(m.Channel, fmt.Sprintf("dropped %s and took %s from %s", removed, i, m.User.Name))
|
||||||
|
} else {
|
||||||
|
p.bot.SendAction(m.Channel, fmt.Sprintf("takes %s from %s", i, m.User.Name))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkerr(e error) {
|
||||||
|
if e != nil {
|
||||||
|
log.Println(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// nothing to register
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -311,10 +311,7 @@ func (s *Slack) buildMessage(m slackMessage) msg.Message {
|
||||||
|
|
||||||
isCmd, text := bot.IsCmd(s.config, text)
|
isCmd, text := bot.IsCmd(s.config, text)
|
||||||
|
|
||||||
isAction := strings.HasPrefix(text, "/me ")
|
isAction := m.SubType == "me_message"
|
||||||
if isAction {
|
|
||||||
text = text[3:]
|
|
||||||
}
|
|
||||||
|
|
||||||
u := s.getUser(m.User)
|
u := s.getUser(m.User)
|
||||||
if m.Username != "" {
|
if m.Username != "" {
|
||||||
|
|
Loading…
Reference in New Issue