Convert downtime to SQL

This commit is contained in:
Chris Sexton 2016-01-15 13:37:54 -05:00
parent 92e1ea5d42
commit 72b71de10e
3 changed files with 112 additions and 48 deletions

View File

@ -58,7 +58,7 @@ func main() {
// Bot.AddHandler(plugins.NewTestPlugin(Bot)) // Bot.AddHandler(plugins.NewTestPlugin(Bot))
Bot.AddHandler("admin", plugins.NewAdminPlugin(Bot)) Bot.AddHandler("admin", plugins.NewAdminPlugin(Bot))
Bot.AddHandler("first", plugins.NewFirstPlugin(Bot)) Bot.AddHandler("first", plugins.NewFirstPlugin(Bot))
// Bot.AddHandler("downtime", plugins.NewDowntimePlugin(Bot)) Bot.AddHandler("downtime", plugins.NewDowntimePlugin(Bot))
Bot.AddHandler("talker", plugins.NewTalkerPlugin(Bot)) Bot.AddHandler("talker", plugins.NewTalkerPlugin(Bot))
Bot.AddHandler("dice", plugins.NewDicePlugin(Bot)) Bot.AddHandler("dice", plugins.NewDicePlugin(Bot))
Bot.AddHandler("beers", plugins.NewBeersPlugin(Bot)) Bot.AddHandler("beers", plugins.NewBeersPlugin(Bot))

View File

@ -2,7 +2,11 @@
package plugins package plugins
import "github.com/chrissexton/alepale/bot" import (
"database/sql"
"github.com/chrissexton/alepale/bot"
)
import ( import (
"fmt" "fmt"
@ -10,21 +14,74 @@ import (
"sort" "sort"
"strings" "strings"
"time" "time"
"labix.org/v2/mgo"
"labix.org/v2/mgo/bson"
) )
// This is a downtime plugin to monitor how much our users suck // This is a downtime plugin to monitor how much our users suck
type DowntimePlugin struct { type DowntimePlugin struct {
Bot *bot.Bot Bot *bot.Bot
Coll *mgo.Collection db *sql.DB
} }
type idleEntry struct { type idleEntry struct {
Nick string id sql.NullInt64
LastSeen time.Time nick string
lastSeen time.Time
}
func (entry idleEntry) saveIdleEntry(db *sql.DB) error {
var err error
if entry.id.Valid {
log.Println("Updating downtime for: ", entry)
_, err = db.Exec(`update downtime set
nick=?, lastSeen=?
where id=?;`, entry.nick, entry.lastSeen.Unix(), entry.id.Int64)
} else {
log.Println("Inserting downtime for: ", entry)
_, err = db.Exec(`insert into downtime (nick, lastSeen)
values (?, ?)`, entry.nick, entry.lastSeen.Unix())
}
return err
}
func getIdleEntryByNick(db *sql.DB, nick string) (idleEntry, error) {
var id sql.NullInt64
var lastSeen sql.NullInt64
err := db.QueryRow(`select id, max(lastSeen) from downtime
where nick = ?`, nick).Scan(&id, &lastSeen)
if err != nil {
log.Println("Error selecting downtime: ", err)
return idleEntry{}, err
}
if !id.Valid {
return idleEntry{
nick: nick,
lastSeen: time.Now(),
}, nil
}
return idleEntry{
id: id,
nick: nick,
lastSeen: time.Unix(lastSeen.Int64, 0),
}, nil
}
func getAllIdleEntries(db *sql.DB) (idleEntries, error) {
rows, err := db.Query(`select id, nick, max(lastSeen) from downtime
group by nick`)
if err != nil {
return nil, err
}
entries := idleEntries{}
for rows.Next() {
var e idleEntry
err := rows.Scan(&e.id, &e.nick, &e.lastSeen)
if err != nil {
return nil, err
}
entries = append(entries, &e)
}
return entries, nil
} }
type idleEntries []*idleEntry type idleEntries []*idleEntry
@ -34,7 +91,7 @@ func (ie idleEntries) Len() int {
} }
func (ie idleEntries) Less(i, j int) bool { func (ie idleEntries) Less(i, j int) bool {
return ie[i].LastSeen.Before(ie[j].LastSeen) return ie[i].lastSeen.Before(ie[j].lastSeen)
} }
func (ie idleEntries) Swap(i, j int) { func (ie idleEntries) Swap(i, j int) {
@ -45,8 +102,20 @@ func (ie idleEntries) Swap(i, j int) {
func NewDowntimePlugin(bot *bot.Bot) *DowntimePlugin { func NewDowntimePlugin(bot *bot.Bot) *DowntimePlugin {
p := DowntimePlugin{ p := DowntimePlugin{
Bot: bot, Bot: bot,
db: bot.DB,
} }
p.LoadData()
if bot.DBVersion == 1 {
_, err := p.db.Exec(`create table if not exists downtime (
id integer primary key,
nick string,
lastSeen integer
);`)
if err != nil {
log.Fatal("Error creating downtime table: ", err)
}
}
return &p return &p
} }
@ -63,29 +132,33 @@ func (p *DowntimePlugin) Message(message bot.Message) bool {
if parts[0] == "idle" && len(parts) == 2 { if parts[0] == "idle" && len(parts) == 2 {
nick := parts[1] nick := parts[1]
// parts[1] must be the userid, or we don't know them // parts[1] must be the userid, or we don't know them
var entry idleEntry entry, err := getIdleEntryByNick(p.db, nick)
p.Coll.Find(bson.M{"nick": nick}).One(&entry) if err != nil {
if entry.Nick != nick { log.Println("Error getting idle entry: ", err)
}
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.SendMessage(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.SendMessage(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
} else if parts[0] == "idle" && len(parts) == 1 { } else if parts[0] == "idle" && len(parts) == 1 {
// Find all idle times, report them. // Find all idle times, report them.
var entries idleEntries entries, err := getAllIdleEntries(p.db)
p.Coll.Find(nil).All(&entries) if err != nil {
log.Println("Error retrieving idle entries: ", err)
}
sort.Sort(entries) sort.Sort(entries)
tops := "The top entries are: " tops := "The top entries are: "
for _, e := range entries { for _, e := range entries {
// filter out ZNC entries and ourself // filter out ZNC entries and ourself
if strings.HasPrefix(e.Nick, "*") || strings.ToLower(p.Bot.Config.Nick) == e.Nick { if strings.HasPrefix(e.nick, "*") || strings.ToLower(p.Bot.Config.Nick) == e.nick {
p.remove(e.Nick) p.remove(e.nick)
} else { } else {
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.SendMessage(channel, tops)
@ -99,34 +172,23 @@ func (p *DowntimePlugin) Message(message bot.Message) bool {
} }
func (p *DowntimePlugin) record(user string) { func (p *DowntimePlugin) record(user string) {
var entry idleEntry entry, err := getIdleEntryByNick(p.db, user)
p.Coll.Find(bson.M{"nick": user}).One(&entry) if err != nil {
if entry.Nick != user { log.Println("Error recording downtime: ", err)
// insert a new entry
p.Coll.Upsert(bson.M{"nick": user}, idleEntry{
Nick: user,
LastSeen: time.Now(),
})
log.Println("Inserted downtime for:", user)
} else {
// Update their entry, they were baaaaaad
entry.LastSeen = time.Now()
p.Coll.Upsert(bson.M{"nick": entry.Nick}, entry)
} }
entry.lastSeen = time.Now()
entry.saveIdleEntry(p.db)
log.Println("Inserted downtime for:", user)
} }
func (p *DowntimePlugin) remove(user string) { func (p *DowntimePlugin) remove(user string) error {
p.Coll.RemoveAll(bson.M{"nick": user}) _, err := p.db.Exec(`delete from downtime where nick = ?`, user)
if err != nil {
log.Println("Error removing downtime for user: ", user, err)
return err
}
log.Println("Removed downtime for:", user) log.Println("Removed downtime for:", user)
} return nil
// LoadData imports any configuration data into the plugin. This is not strictly necessary other
// than the fact that the Plugin interface demands it exist. This may be deprecated at a later
// date.
func (p *DowntimePlugin) LoadData() {
// Mongo is removed, this plugin will crash if started
log.Fatal("The Downtime plugin has not been upgraded to SQL yet.")
// p.Coll = p.Bot.Db.C("downtime")
} }
// Help responds to help requests. Every plugin must implement a help function. // Help responds to help requests. Every plugin must implement a help function.

View File

@ -34,8 +34,8 @@ type FirstEntry struct {
func (fe *FirstEntry) save(db *sql.DB) error { func (fe *FirstEntry) save(db *sql.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, fe.day.Unix(),
fe.time, fe.time.Unix(),
fe.body, fe.body,
fe.nick, fe.nick,
); err != nil { ); err != nil {
@ -49,8 +49,8 @@ func NewFirstPlugin(b *bot.Bot) *FirstPlugin {
if b.DBVersion == 1 { if b.DBVersion == 1 {
_, err := b.DB.Exec(`create table if not exists first ( _, err := b.DB.Exec(`create table if not exists first (
id integer primary key, id integer primary key,
day datetime, day integer,
time datetime, time integer,
body string, body string,
nick string nick string
);`) );`)
@ -96,8 +96,10 @@ func getLastFirst(db *sql.DB) (*FirstEntry, error) {
log.Println("No previous first entries") log.Println("No previous first entries")
return nil, nil return nil, nil
case err != nil: case err != nil:
log.Println("Error on first query row: ", err)
return nil, err return nil, err
} }
log.Println(id, day, timeEntered, body, nick)
return &FirstEntry{ return &FirstEntry{
id: id.Int64, id: id.Int64,
day: time.Unix(day.Int64, 0), day: time.Unix(day.Int64, 0),