Merge branch 'counterstuff'

* counterstuff:
  Fix #19: Merge beers and counters
  Migrate to sqlx; modularize counters
  Move counter to its own package
  Fix a few minor govet issues
This commit is contained in:
Chris Sexton 2016-03-19 14:30:22 -04:00
commit 15602defbc
10 changed files with 172 additions and 154 deletions

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/config" "github.com/velour/catbase/config"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
@ -35,7 +36,7 @@ type Bot struct {
// TODO: I think it'd be nice to use https://github.com/jmoiron/sqlx so that // TODO: I think it'd be nice to use https://github.com/jmoiron/sqlx so that
// the select/update/etc statements could be simplified with struct // the select/update/etc statements could be simplified with struct
// marshalling. // marshalling.
DB *sql.DB DB *sqlx.DB
DBVersion int64 DBVersion int64
logIn chan Message logIn chan Message
@ -98,7 +99,7 @@ type Variable struct {
// NewBot creates a Bot for a given connection and set of handlers. // NewBot creates a Bot for a given connection and set of handlers.
func NewBot(config *config.Config, connector Connector) *Bot { func NewBot(config *config.Config, connector Connector) *Bot {
sqlDB, err := sql.Open("sqlite3", config.DB.File) sqlDB, err := sqlx.Open("sqlite3", config.DB.File)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/velour/catbase/config" "github.com/velour/catbase/config"
"github.com/velour/catbase/irc" "github.com/velour/catbase/irc"
"github.com/velour/catbase/plugins" "github.com/velour/catbase/plugins"
"github.com/velour/catbase/plugins/counter"
"github.com/velour/catbase/slack" "github.com/velour/catbase/slack"
) )
@ -39,7 +40,7 @@ func main() {
b.AddHandler("talker", plugins.NewTalkerPlugin(b)) b.AddHandler("talker", plugins.NewTalkerPlugin(b))
b.AddHandler("dice", plugins.NewDicePlugin(b)) b.AddHandler("dice", plugins.NewDicePlugin(b))
b.AddHandler("beers", plugins.NewBeersPlugin(b)) b.AddHandler("beers", plugins.NewBeersPlugin(b))
b.AddHandler("counter", plugins.NewCounterPlugin(b)) b.AddHandler("counter", counter.NewCounterPlugin(b))
b.AddHandler("remember", plugins.NewRememberPlugin(b)) b.AddHandler("remember", plugins.NewRememberPlugin(b))
b.AddHandler("skeleton", plugins.NewSkeletonPlugin(b)) b.AddHandler("skeleton", plugins.NewSkeletonPlugin(b))
b.AddHandler("your", plugins.NewYourPlugin(b)) b.AddHandler("your", plugins.NewYourPlugin(b))

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
) )
@ -17,7 +18,7 @@ import (
type AdminPlugin struct { type AdminPlugin struct {
Bot *bot.Bot Bot *bot.Bot
DB *sql.DB DB *sqlx.DB
} }
// NewAdminPlugin creates a new AdminPlugin with the Plugin interface // NewAdminPlugin creates a new AdminPlugin with the Plugin interface

View File

@ -3,7 +3,6 @@
package plugins package plugins
import ( import (
"database/sql"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -15,22 +14,16 @@ import (
"strings" "strings"
"time" "time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
"github.com/velour/catbase/plugins/counter"
) )
// This is a skeleton plugin to serve as an example and quick copy/paste for new plugins. // This is a skeleton plugin to serve as an example and quick copy/paste for new plugins.
type BeersPlugin struct { type BeersPlugin struct {
Bot *bot.Bot Bot *bot.Bot
db *sql.DB db *sqlx.DB
}
type userBeers struct {
id int64
nick string
count int
lastDrunk time.Time
saved bool
} }
type untappdUser struct { type untappdUser struct {
@ -74,58 +67,6 @@ func NewBeersPlugin(bot *bot.Bot) *BeersPlugin {
return &p return &p
} }
func (u *userBeers) Save(db *sql.DB) error {
if !u.saved {
res, err := db.Exec(`insert into beers (
nick,
count,
lastDrunk
) values (?, ?, ?)`, u.nick, u.count, u.lastDrunk)
if err != nil {
return err
}
id, err := res.LastInsertId()
if err != nil {
return err
}
u.id = id
} else {
_, err := db.Exec(`update beers set
count = ?,
lastDrunk = ?
where id = ?;`, u.count, time.Now(), u.id)
if err != nil {
log.Println("Error updating beers: ", err)
return err
}
}
return nil
}
func getUserBeers(db *sql.DB, nick string) *userBeers {
ub := userBeers{saved: true}
err := db.QueryRow(`select id, nick, count, lastDrunk from beers
where nick = ?`, nick).Scan(
&ub.id,
&ub.nick,
&ub.count,
&ub.lastDrunk,
)
if err == sql.ErrNoRows {
log.Println("DIDN'T FIND THAT USER: ", err)
return &userBeers{
nick: nick,
count: 0,
}
}
if err != nil && err != sql.ErrNoRows {
log.Println("Error finding beers: ", err)
return nil
}
return &ub
}
// 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.
@ -159,7 +100,7 @@ func (p *BeersPlugin) Message(message bot.Message) bool {
return true return true
} }
if parts[1] == "+=" { if parts[1] == "+=" {
p.setBeers(nick, p.getBeers(nick)+count) p.addBeers(nick, count)
p.randomReply(channel) p.randomReply(channel)
} else if parts[1] == "=" { } else if parts[1] == "=" {
if count == 0 { if count == 0 {
@ -185,16 +126,15 @@ func (p *BeersPlugin) Message(message bot.Message) bool {
// no matter what, if we're in here, then we've responded // no matter what, if we're in here, then we've responded
return true return true
} else if parts[0] == "beers--" { } else if parts[0] == "beers--" {
p.setBeers(nick, p.getBeers(nick)-1) p.addBeers(nick, -1)
p.Bot.SendAction(channel, "flushes") p.Bot.SendAction(channel, "flushes")
return true return true
} else if parts[0] == "beers++" { } else if parts[0] == "beers++" {
p.addBeers(nick) p.addBeers(nick, 1)
p.randomReply(channel) p.randomReply(channel)
return true return true
} else if parts[0] == "bourbon++" { } else if parts[0] == "bourbon++" {
p.addBeers(nick) p.addBeers(nick, 2)
p.addBeers(nick)
p.randomReply(channel) p.randomReply(channel)
return true return true
} else if parts[0] == "puke" { } else if parts[0] == "puke" {
@ -203,7 +143,7 @@ func (p *BeersPlugin) Message(message bot.Message) bool {
} }
if message.Command && parts[0] == "imbibe" { if message.Command && parts[0] == "imbibe" {
p.addBeers(nick) p.addBeers(nick, 1)
p.randomReply(channel) p.randomReply(channel)
return true return true
} }
@ -291,22 +231,30 @@ func (p *BeersPlugin) Help(channel string, parts []string) {
p.Bot.SendMessage(channel, msg) p.Bot.SendMessage(channel, msg)
} }
func getUserBeers(db *sqlx.DB, user string) counter.Item {
booze, _ := counter.GetItem(db, user, "booze")
return booze
}
func (p *BeersPlugin) setBeers(user string, amount int) { func (p *BeersPlugin) setBeers(user string, amount int) {
ub := getUserBeers(p.db, user) ub := getUserBeers(p.db, user)
ub.count = amount err := ub.Update(amount)
ub.lastDrunk = time.Now() if err != nil {
if err := ub.Save(p.db); err != nil {
log.Println("Error saving beers: ", err) log.Println("Error saving beers: ", err)
} }
} }
func (p *BeersPlugin) addBeers(user string) { func (p *BeersPlugin) addBeers(user string, delta int) {
p.setBeers(user, p.getBeers(user)+1) ub := getUserBeers(p.db, user)
err := ub.UpdateDelta(delta)
if err != nil {
log.Println("Error saving beers: ", err)
}
} }
func (p *BeersPlugin) getBeers(nick string) int { func (p *BeersPlugin) getBeers(nick string) int {
ub := getUserBeers(p.db, nick) ub := getUserBeers(p.db, nick)
return ub.count return ub.Count
} }
func (p *BeersPlugin) reportCount(nick, channel string, himself bool) { func (p *BeersPlugin) reportCount(nick, channel string, himself bool) {
@ -401,7 +349,8 @@ func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
} }
func (p *BeersPlugin) checkUntappd(channel string) { func (p *BeersPlugin) checkUntappd(channel string) {
if p.Bot.Config.Untappd.Token == "<Your Token>" { token := p.Bot.Config.Untappd.Token
if token == "" || token == "<Your Token>" {
log.Println("No Untappd token, cannot enable plugin.") log.Println("No Untappd token, cannot enable plugin.")
return return
} }
@ -450,7 +399,7 @@ func (p *BeersPlugin) checkUntappd(channel string) {
} }
log.Printf("user.chanNick: %s, user.untappdUser: %s, checkin.User.User_name: %s", log.Printf("user.chanNick: %s, user.untappdUser: %s, checkin.User.User_name: %s",
user.chanNick, user.untappdUser, checkin.User.User_name) user.chanNick, user.untappdUser, checkin.User.User_name)
p.addBeers(user.chanNick) p.addBeers(user.chanNick, 1)
drunken := p.getBeers(user.chanNick) drunken := p.getBeers(user.chanNick)
msg := fmt.Sprintf("%s just drank %s by %s%s, bringing his drunkeness to %d", msg := fmt.Sprintf("%s just drank %s by %s%s, bringing his drunkeness to %d",

View File

@ -1,6 +1,6 @@
// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors. // © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors.
package plugins package counter
import ( import (
"database/sql" "database/sql"
@ -8,6 +8,7 @@ import (
"log" "log"
"strings" "strings"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
) )
@ -15,16 +16,91 @@ import (
type CounterPlugin struct { type CounterPlugin struct {
Bot *bot.Bot Bot *bot.Bot
DB *sql.DB DB *sqlx.DB
} }
type Item struct { type Item struct {
*sqlx.DB
ID int64 ID int64
Nick string Nick string
Item string Item string
Count int Count int
} }
// GetItems returns all counters for a subject
func GetItems(db *sqlx.DB, nick string) ([]Item, error) {
var items []Item
err := db.Select(&items, `select * from counter where nick = ?`, nick)
if err != nil {
return nil, err
}
// Don't forget to embed the DB into all of that shiz
for _, i := range items {
i.DB = db
}
return items, nil
}
// GetItem returns a specific counter for a subject
func GetItem(db *sqlx.DB, nick, itemName string) (Item, error) {
var item Item
item.DB = db
log.Printf("GetItem db: %#v", db)
err := db.Get(&item, `select * from counter where nick = ? and item= ?`,
nick, itemName)
switch err {
case sql.ErrNoRows:
item.ID = -1
item.Nick = nick
item.Item = itemName
case nil:
default:
return Item{}, err
}
log.Printf("Got item %s.%s: %#v", nick, itemName, item)
return item, nil
}
// Create saves a counter
func (i *Item) Create() error {
res, err := i.Exec(`insert into counter (nick, item, count) values (?, ?, ?);`,
i.Nick, i.Item, i.Count)
id, _ := res.LastInsertId()
// hackhackhack?
i.ID = id
return err
}
// UpdateDelta sets a value
// This will create or delete the item if necessary
func (i *Item) Update(value int) error {
i.Count = value
if i.Count == 0 && i.ID != -1 {
return i.Delete()
}
if i.ID == -1 {
i.Create()
}
log.Printf("Updating item: %#v, value: %d", i, value)
_, err := i.Exec(`update counter set count = ? where id = ?`, i.Count, i.ID)
return err
}
// UpdateDelta changes a value according to some delta
// This will create or delete the item if necessary
func (i *Item) UpdateDelta(delta int) error {
i.Count += delta
return i.Update(i.Count)
}
// Delete removes a counter from the database
func (i *Item) Delete() error {
_, err := i.Exec(`delete from counter where id = ?`, i.ID)
i.ID = -1
return err
}
// NewCounterPlugin creates a new CounterPlugin with the Plugin interface // NewCounterPlugin creates a new CounterPlugin with the Plugin interface
func NewCounterPlugin(bot *bot.Bot) *CounterPlugin { func NewCounterPlugin(bot *bot.Bot) *CounterPlugin {
if bot.DBVersion == 1 { if bot.DBVersion == 1 {
@ -63,36 +139,32 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
if parts[1] == "me" { if parts[1] == "me" {
subject = strings.ToLower(nick) subject = strings.ToLower(nick)
} else { } else {
subject = parts[1] subject = strings.ToLower(parts[1])
} }
log.Printf("Getting counter for %s", subject) log.Printf("Getting counter for %s", subject)
// pull all of the items associated with "subject" // pull all of the items associated with "subject"
rows, err := p.DB.Query(`select nick, item, count from counter where nick = ?`, subject) items, err := GetItems(p.DB, subject)
if err != nil { if err != nil {
log.Fatal(err) log.Fatalf("Error retrieving items for %s: %s", subject, err)
p.Bot.SendMessage(channel, "Something went wrong finding that counter;")
return true
} }
resp := fmt.Sprintf("%s has the following counters:", subject) resp := fmt.Sprintf("%s has the following counters:", subject)
count := 0 count := 0
for rows.Next() { for _, it := range items {
count += 1 count += 1
var it Item
err := rows.Scan(&it.Nick, &it.Item, &it.Count)
if err != nil {
log.Printf("Error getting counter: %s", err)
}
if count > 1 { if count > 1 {
resp = fmt.Sprintf("%s, ", resp) resp += ", "
} }
resp = fmt.Sprintf("%s %s: %d", resp, it.Item, it.Count) resp += fmt.Sprintf(" %s: %d", it.Item, it.Count)
if count > 20 { if count > 20 {
fmt.Sprintf("%s, and a few others", resp) resp += ", and a few others"
break break
} }
} }
resp = fmt.Sprintf("%s.", resp) resp += "."
if count == 0 { if count == 0 {
p.Bot.SendMessage(channel, fmt.Sprintf("%s has no counters.", subject)) p.Bot.SendMessage(channel, fmt.Sprintf("%s has no counters.", subject))
@ -105,7 +177,15 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
subject := strings.ToLower(nick) subject := strings.ToLower(nick)
itemName := strings.ToLower(parts[1]) itemName := strings.ToLower(parts[1])
if _, err := p.DB.Exec(`delete from counter where nick = ? and item = ?`, subject, itemName); err != nil { it, err := GetItem(p.DB, subject, itemName)
if err != nil {
log.Printf("Error getting item to remove %s.%s: %s", subject, itemName, err)
p.Bot.SendMessage(channel, "Something went wrong removing that counter;")
return true
}
err = it.Delete()
if err != nil {
log.Printf("Error removing item %s.%s: %s", subject, itemName, err)
p.Bot.SendMessage(channel, "Something went wrong removing that counter;") p.Bot.SendMessage(channel, "Something went wrong removing that counter;")
return true return true
} }
@ -130,17 +210,15 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
} }
var item Item var item Item
err := p.DB.QueryRow(`select nick, item, count from counter item, err := GetItem(p.DB, subject, itemName)
where nick = ? and item = ?`, subject, itemName).Scan(
&item.Nick, &item.Item, &item.Count,
)
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.SendMessage(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:
log.Println(err) log.Printf("Error retrieving item count for %s.%s: %s",
subject, itemName, err)
return true return true
} }
@ -149,6 +227,7 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
return true return true
} else if len(parts) == 1 { } else if len(parts) == 1 {
// Need to have at least 3 characters to ++ or --
if len(parts[0]) < 3 { if len(parts[0]) < 3 {
return false return false
} }
@ -163,13 +242,26 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
if strings.HasSuffix(parts[0], "++") { if strings.HasSuffix(parts[0], "++") {
// ++ those fuckers // ++ those fuckers
item := p.update(subject, itemName, 1) item, err := GetItem(p.DB, subject, itemName)
if err != nil {
log.Printf("Error finding item %s.%s: %s.", subject, itemName, err)
// Item ain't there, I guess
return false
}
log.Printf("About to update item: %#v", item)
item.UpdateDelta(1)
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.SendMessage(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], "--") {
// -- those fuckers // -- those fuckers
item := p.update(subject, itemName, -1) item, err := GetItem(p.DB, subject, itemName)
if err != nil {
log.Printf("Error finding item %s.%s: %s.", subject, itemName, err)
// Item ain't there, I guess
return false
}
item.UpdateDelta(-1)
p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject, p.Bot.SendMessage(channel, fmt.Sprintf("%s has %d %s.", subject,
item.Count, item.Item)) item.Count, item.Item))
return true return true
@ -179,35 +271,6 @@ func (p *CounterPlugin) Message(message bot.Message) bool {
return false return false
} }
func (p *CounterPlugin) update(subject, itemName string, delta int) Item {
var item Item
err := p.DB.QueryRow(`select id, nick, item, count from counter
where nick = ? and item = ?;`, subject, itemName).Scan(
&item.ID, &item.Nick, &item.Item, &item.Count,
)
switch {
case err == sql.ErrNoRows:
// insert it
res, err := p.DB.Exec(`insert into counter (nick, item, count)
values (?, ?, ?)`, subject, itemName, delta)
if err != nil {
log.Println(err)
}
id, err := res.LastInsertId()
return Item{id, subject, itemName, delta}
case err != nil:
log.Println(err)
return item
default:
item.Count += delta
_, err := p.DB.Exec(`update counter set count = ? where id = ?`, item.Count, item.ID)
if err != nil {
log.Println(err)
}
return item
}
}
// LoadData imports any configuration data into the plugin. This is not // LoadData imports any configuration data into the plugin. This is not
// strictly necessary other than the fact that the Plugin interface demands it // strictly necessary other than the fact that the Plugin interface demands it
// exist. This may be deprecated at a later date. // exist. This may be deprecated at a later date.

View File

@ -5,6 +5,7 @@ package plugins
import ( import (
"database/sql" "database/sql"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
) )
@ -20,7 +21,7 @@ import (
type DowntimePlugin struct { type DowntimePlugin struct {
Bot *bot.Bot Bot *bot.Bot
db *sql.DB db *sqlx.DB
} }
type idleEntry struct { type idleEntry struct {
@ -29,7 +30,7 @@ type idleEntry struct {
lastSeen time.Time lastSeen time.Time
} }
func (entry idleEntry) saveIdleEntry(db *sql.DB) error { func (entry idleEntry) saveIdleEntry(db *sqlx.DB) error {
var err error var err error
if entry.id.Valid { if entry.id.Valid {
log.Println("Updating downtime for: ", entry) log.Println("Updating downtime for: ", entry)
@ -44,7 +45,7 @@ func (entry idleEntry) saveIdleEntry(db *sql.DB) error {
return err return err
} }
func getIdleEntryByNick(db *sql.DB, nick string) (idleEntry, error) { func getIdleEntryByNick(db *sqlx.DB, nick string) (idleEntry, error) {
var id sql.NullInt64 var id sql.NullInt64
var lastSeen sql.NullInt64 var lastSeen sql.NullInt64
err := db.QueryRow(`select id, max(lastSeen) from downtime err := db.QueryRow(`select id, max(lastSeen) from downtime
@ -66,7 +67,7 @@ func getIdleEntryByNick(db *sql.DB, nick string) (idleEntry, error) {
}, nil }, nil
} }
func getAllIdleEntries(db *sql.DB) (idleEntries, error) { func getAllIdleEntries(db *sqlx.DB) (idleEntries, error) {
rows, err := db.Query(`select id, nick, max(lastSeen) from downtime rows, err := db.Query(`select id, nick, max(lastSeen) from downtime
group by nick`) group by nick`)
if err != nil { if err != nil {

View File

@ -13,6 +13,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
) )
@ -31,7 +32,7 @@ type factoid struct {
count int count int
} }
func (f *factoid) save(db *sql.DB) error { func (f *factoid) save(db *sqlx.DB) error {
var err error var err error
if f.id.Valid { if f.id.Valid {
// update // update
@ -82,7 +83,7 @@ func (f *factoid) save(db *sql.DB) error {
return err return err
} }
func (f *factoid) delete(db *sql.DB) error { func (f *factoid) delete(db *sqlx.DB) error {
var err error var err error
if f.id.Valid { if f.id.Valid {
_, err = db.Exec(`delete from factoid where id=?`, f.id) _, err = db.Exec(`delete from factoid where id=?`, f.id)
@ -91,7 +92,7 @@ func (f *factoid) delete(db *sql.DB) error {
return err return err
} }
func getFacts(db *sql.DB, fact string) ([]*factoid, error) { func getFacts(db *sqlx.DB, fact string) ([]*factoid, error) {
var fs []*factoid var fs []*factoid
rows, err := db.Query(`select rows, err := db.Query(`select
id, id,
@ -129,7 +130,7 @@ func getFacts(db *sql.DB, fact string) ([]*factoid, error) {
return fs, err return fs, err
} }
func getSingle(db *sql.DB) (*factoid, error) { func getSingle(db *sqlx.DB) (*factoid, error) {
var f factoid var f factoid
var tmpCreated int64 var tmpCreated int64
var tmpAccessed int64 var tmpAccessed int64
@ -158,7 +159,7 @@ func getSingle(db *sql.DB) (*factoid, error) {
return &f, err return &f, err
} }
func getSingleFact(db *sql.DB, fact string) (*factoid, error) { func getSingleFact(db *sqlx.DB, fact string) (*factoid, error) {
var f factoid var f factoid
var tmpCreated int64 var tmpCreated int64
var tmpAccessed int64 var tmpAccessed int64
@ -194,7 +195,7 @@ type FactoidPlugin struct {
Bot *bot.Bot Bot *bot.Bot
NotFound []string NotFound []string
LastFact *factoid LastFact *factoid
db *sql.DB db *sqlx.DB
} }
// NewFactoidPlugin creates a new FactoidPlugin with the Plugin interface // NewFactoidPlugin creates a new FactoidPlugin with the Plugin interface
@ -229,18 +230,18 @@ func NewFactoidPlugin(botInst *bot.Bot) *FactoidPlugin {
for _, channel := range botInst.Config.Channels { for _, channel := range botInst.Config.Channels {
go p.factTimer(channel) go p.factTimer(channel)
go func() { go func(ch string) {
// Some random time to start up // Some random time to start up
time.Sleep(time.Duration(15) * time.Second) time.Sleep(time.Duration(15) * time.Second)
if ok, fact := p.findTrigger(p.Bot.Config.StartupFact); ok { if ok, fact := p.findTrigger(p.Bot.Config.StartupFact); ok {
p.sayFact(bot.Message{ p.sayFact(bot.Message{
Channel: channel, Channel: ch,
Body: "speed test", // BUG: This is defined in the config too Body: "speed test", // BUG: This is defined in the config too
Command: true, Command: true,
Action: false, Action: false,
}, *fact) }, *fact)
} }
}() }(channel)
} }
return p return p

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
) )
@ -18,7 +19,7 @@ import (
type FirstPlugin struct { type FirstPlugin struct {
First *FirstEntry First *FirstEntry
Bot *bot.Bot Bot *bot.Bot
db *sql.DB db *sqlx.DB
} }
type FirstEntry struct { type FirstEntry struct {
@ -31,7 +32,7 @@ type FirstEntry struct {
} }
// Insert or update the first entry // Insert or update the first entry
func (fe *FirstEntry) save(db *sql.DB) error { func (fe *FirstEntry) save(db *sqlx.DB) error {
if _, err := db.Exec(`insert into first (day, time, body, nick) if _, err := db.Exec(`insert into first (day, time, body, nick)
values (?, ?, ?, ?)`, values (?, ?, ?, ?)`,
fe.day.Unix(), fe.day.Unix(),
@ -73,7 +74,7 @@ func NewFirstPlugin(b *bot.Bot) *FirstPlugin {
} }
} }
func getLastFirst(db *sql.DB) (*FirstEntry, error) { func getLastFirst(db *sqlx.DB) (*FirstEntry, error) {
// Get last first entry // Get last first entry
var id sql.NullInt64 var id sql.NullInt64
var day sql.NullInt64 var day sql.NullInt64

View File

@ -3,13 +3,13 @@
package plugins package plugins
import ( import (
"database/sql"
"fmt" "fmt"
"log" "log"
"math/rand" "math/rand"
"strings" "strings"
"time" "time"
"github.com/jmoiron/sqlx"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
) )
@ -19,7 +19,7 @@ import (
type RememberPlugin struct { type RememberPlugin struct {
Bot *bot.Bot Bot *bot.Bot
Log map[string][]bot.Message Log map[string][]bot.Message
db *sql.DB db *sqlx.DB
} }
// NewRememberPlugin creates a new RememberPlugin with the Plugin interface // NewRememberPlugin creates a new RememberPlugin with the Plugin interface

View File

@ -1,4 +1,4 @@
// Package to connect to slack service // Package slack connects to slack service
package slack package slack
import ( import (
@ -113,7 +113,7 @@ func (s *Slack) Serve() {
for { for {
msg, err := s.receiveMessage() msg, err := s.receiveMessage()
if err != nil { if err != nil {
log.Printf("Slack API error: ", err) log.Fatalf("Slack API error: %s", err)
} }
switch msg.Type { switch msg.Type {
case "message": case "message":
@ -134,7 +134,7 @@ func (s *Slack) Serve() {
// Convert a slackMessage to a bot.Message // Convert a slackMessage to a bot.Message
func (s *Slack) buildMessage(msg slackMessage) bot.Message { func (s *Slack) buildMessage(msg slackMessage) bot.Message {
log.Println("DEBUG: msg: %%#v", msg) log.Printf("DEBUG: msg: %#v", msg)
text := html.UnescapeString(msg.Text) text := html.UnescapeString(msg.Text)
isCmd, text := bot.IsCmd(s.config, text) isCmd, text := bot.IsCmd(s.config, text)