mirror of https://github.com/velour/catbase.git
stats: Add a day categorization above all others
This commit is contained in:
parent
de19f6a4e9
commit
4213243744
|
@ -31,9 +31,17 @@ func New(bot bot.Bot) *StatsPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
type stat struct {
|
type stat struct {
|
||||||
|
// date formatted: "2006-01-02"
|
||||||
|
day string
|
||||||
|
// category
|
||||||
bucket string
|
bucket string
|
||||||
key string
|
// specific unique individual
|
||||||
val value
|
key string
|
||||||
|
val value
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkDay() string {
|
||||||
|
return time.Now().Format("2006-01-02")
|
||||||
}
|
}
|
||||||
|
|
||||||
// The value type is here in the future growth case that we might want to put a
|
// The value type is here in the future growth case that we might want to put a
|
||||||
|
@ -53,13 +61,16 @@ func valueFromBytes(b []byte) (value, error) {
|
||||||
|
|
||||||
type stats []stat
|
type stats []stat
|
||||||
|
|
||||||
func mkStat(bucket, key, val []byte) (stat, error) {
|
// mkStat converts raw data to a stat struct
|
||||||
|
// Expected a string representation of the date formatted: "2006-01-02"
|
||||||
|
func mkStat(day string, bucket, key, val []byte) (stat, error) {
|
||||||
v, err := valueFromBytes(val)
|
v, err := valueFromBytes(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("mkStat: error getting value from bytes: %s", err)
|
log.Printf("mkStat: error getting value from bytes: %s", err)
|
||||||
return stat{}, err
|
return stat{}, err
|
||||||
}
|
}
|
||||||
return stat{
|
return stat{
|
||||||
|
day: day,
|
||||||
bucket: string(bucket),
|
bucket: string(bucket),
|
||||||
key: string(key),
|
key: string(key),
|
||||||
val: v,
|
val: v,
|
||||||
|
@ -71,7 +82,9 @@ func (v value) add(other value) value {
|
||||||
return v + other
|
return v + other
|
||||||
}
|
}
|
||||||
|
|
||||||
func statFromDB(path, bucket, key string) (stat, error) {
|
// statFromDB takes a location specification and returns the data at that path
|
||||||
|
// Expected a string representation of the date formatted: "2006-01-02"
|
||||||
|
func statFromDB(path, day, bucket, key string) (stat, error) {
|
||||||
db, err := bolt.Open(path, 0600, &bolt.Options{
|
db, err := bolt.Open(path, 0600, &bolt.Options{
|
||||||
Timeout: 1 * time.Second,
|
Timeout: 1 * time.Second,
|
||||||
})
|
})
|
||||||
|
@ -90,11 +103,17 @@ func statFromDB(path, bucket, key string) (stat, error) {
|
||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
b, err := tx.CreateBucketIfNotExists(buk)
|
d, err := tx.CreateBucketIfNotExists([]byte(day))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("statFromDB: Error creating the bucket")
|
log.Println("statFromDB: Error creating the bucket")
|
||||||
return stat{}, err
|
return stat{}, err
|
||||||
}
|
}
|
||||||
|
b, err := d.CreateBucketIfNotExists(buk)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("statFromDB: Error creating the bucket")
|
||||||
|
return stat{}, err
|
||||||
|
}
|
||||||
|
|
||||||
v := b.Get(k)
|
v := b.Get(k)
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
|
@ -103,12 +122,13 @@ func statFromDB(path, bucket, key string) (stat, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return stat{bucket, key, 0}, nil
|
return stat{day, bucket, key, 0}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return mkStat(buk, k, v)
|
return mkStat(day, buk, k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toDB takes a stat and records it, adding to the value in the DB if necessary
|
||||||
func (s stats) toDB(path string) error {
|
func (s stats) toDB(path string) error {
|
||||||
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -119,7 +139,12 @@ func (s stats) toDB(path string) error {
|
||||||
|
|
||||||
for _, stat := range s {
|
for _, stat := range s {
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
err = db.Update(func(tx *bolt.Tx) error {
|
||||||
b, err := tx.CreateBucketIfNotExists([]byte(stat.bucket))
|
d, err := tx.CreateBucketIfNotExists([]byte(stat.day))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("toDB: Error creating bucket")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b, err := d.CreateBucketIfNotExists([]byte(stat.bucket))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("toDB: Error creating bucket")
|
log.Println("toDB: Error creating bucket")
|
||||||
return err
|
return err
|
||||||
|
@ -192,24 +217,24 @@ func (p *StatsPlugin) RegisterWeb() *string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *StatsPlugin) mkUserStat(message msg.Message) stats {
|
func (p *StatsPlugin) mkUserStat(message msg.Message) stats {
|
||||||
return stats{stat{"user", message.User.Name, 1}}
|
return stats{stat{mkDay(), "user", message.User.Name, 1}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *StatsPlugin) mkHourStat(message msg.Message) stats {
|
func (p *StatsPlugin) mkHourStat(message msg.Message) stats {
|
||||||
hr := time.Now().Hour()
|
hr := time.Now().Hour()
|
||||||
return stats{stat{"user", string(hr), 1}}
|
return stats{stat{mkDay(), "user", string(hr), 1}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *StatsPlugin) mkSightingStat(message msg.Message) stats {
|
func (p *StatsPlugin) mkSightingStat(message msg.Message) stats {
|
||||||
stats := stats{}
|
stats := stats{}
|
||||||
for _, name := range p.bot.Config().Stats.Sightings {
|
for _, name := range p.bot.Config().Stats.Sightings {
|
||||||
if strings.Contains(message.Body, name+" sighting") {
|
if strings.Contains(message.Body, name+" sighting") {
|
||||||
stats = append(stats, stat{"sighting", name, 1})
|
stats = append(stats, stat{mkDay(), "sighting", name, 1})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *StatsPlugin) mkChannelStat(message msg.Message) stats {
|
func (p *StatsPlugin) mkChannelStat(message msg.Message) stats {
|
||||||
return stats{stat{"channel", message.Channel, 1}}
|
return stats{stat{mkDay(), "channel", message.Channel, 1}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,10 +47,12 @@ func TestWithDB(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestDBReadWrite", func(t *testing.T) {
|
t.Run("TestDBReadWrite", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
bucket := "testBucket"
|
bucket := "testBucket"
|
||||||
key := "testKey"
|
key := "testKey"
|
||||||
|
|
||||||
expected := stats{stat{
|
expected := stats{stat{
|
||||||
|
day,
|
||||||
bucket,
|
bucket,
|
||||||
key,
|
key,
|
||||||
1,
|
1,
|
||||||
|
@ -59,7 +61,7 @@ func TestWithDB(t *testing.T) {
|
||||||
err := expected.toDB(dbPath)
|
err := expected.toDB(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
actual, err := statFromDB(dbPath, bucket, key)
|
actual, err := statFromDB(dbPath, day, bucket, key)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, actual, expected[0])
|
assert.Equal(t, actual, expected[0])
|
||||||
|
@ -69,11 +71,13 @@ func TestWithDB(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestDBAddStatInLoop", func(t *testing.T) {
|
t.Run("TestDBAddStatInLoop", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
bucket := "testBucket"
|
bucket := "testBucket"
|
||||||
key := "testKey"
|
key := "testKey"
|
||||||
expected := value(25)
|
expected := value(25)
|
||||||
|
|
||||||
statPack := stats{stat{
|
statPack := stats{stat{
|
||||||
|
day,
|
||||||
bucket,
|
bucket,
|
||||||
key,
|
key,
|
||||||
5,
|
5,
|
||||||
|
@ -84,7 +88,7 @@ func TestWithDB(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual, err := statFromDB(dbPath, bucket, key)
|
actual, err := statFromDB(dbPath, day, bucket, key)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, actual.val, expected)
|
assert.Equal(t, actual.val, expected)
|
||||||
|
@ -93,42 +97,25 @@ func TestWithDB(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestDBAddStats", func(t *testing.T) {
|
t.Run("TestDBAddStats", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
bucket := "testBucket"
|
bucket := "testBucket"
|
||||||
key := "testKey"
|
key := "testKey"
|
||||||
expected := value(5)
|
expected := value(5)
|
||||||
|
|
||||||
statPack := stats{
|
statPack := stats{}
|
||||||
stat{
|
for i := 0; i < 5; i++ {
|
||||||
|
statPack = append(statPack, stat{
|
||||||
|
day,
|
||||||
bucket,
|
bucket,
|
||||||
key,
|
key,
|
||||||
1,
|
1,
|
||||||
},
|
})
|
||||||
stat{
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
stat{
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
stat{
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
stat{
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := statPack.toDB(dbPath)
|
err := statPack.toDB(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
actual, err := statFromDB(dbPath, bucket, key)
|
actual, err := statFromDB(dbPath, day, bucket, key)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, actual.val, expected)
|
assert.Equal(t, actual.val, expected)
|
||||||
|
@ -151,6 +138,7 @@ func makeMessage(payload string) msg.Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUserCounter(t *testing.T, count int) {
|
func testUserCounter(t *testing.T, count int) {
|
||||||
|
day := mkDay()
|
||||||
expected := value(count)
|
expected := value(count)
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
mb.Cfg.Stats.DBPath = dbPath
|
mb.Cfg.Stats.DBPath = dbPath
|
||||||
|
@ -164,7 +152,7 @@ func testUserCounter(t *testing.T, count int) {
|
||||||
_, err := os.Stat(dbPath)
|
_, err := os.Stat(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
stat, err := statFromDB(mb.Config().Stats.DBPath, "user", "tester")
|
stat, err := statFromDB(mb.Config().Stats.DBPath, day, "user", "tester")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
actual := stat.val
|
actual := stat.val
|
||||||
assert.Equal(t, actual, expected)
|
assert.Equal(t, actual, expected)
|
||||||
|
@ -175,6 +163,7 @@ func TestMessages(t *testing.T) {
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
t.Run("TestOneUserCounter", func(t *testing.T) {
|
t.Run("TestOneUserCounter", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
count := 5
|
count := 5
|
||||||
expected := value(count)
|
expected := value(count)
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
|
@ -189,7 +178,7 @@ func TestMessages(t *testing.T) {
|
||||||
_, err := os.Stat(dbPath)
|
_, err := os.Stat(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
stat, err := statFromDB(mb.Config().Stats.DBPath, "user", "tester")
|
stat, err := statFromDB(mb.Config().Stats.DBPath, day, "user", "tester")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
actual := stat.val
|
actual := stat.val
|
||||||
assert.Equal(t, actual, expected)
|
assert.Equal(t, actual, expected)
|
||||||
|
@ -198,6 +187,7 @@ func TestMessages(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestTenUserCounter", func(t *testing.T) {
|
t.Run("TestTenUserCounter", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
count := 5
|
count := 5
|
||||||
expected := value(count)
|
expected := value(count)
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
|
@ -212,7 +202,7 @@ func TestMessages(t *testing.T) {
|
||||||
_, err := os.Stat(dbPath)
|
_, err := os.Stat(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
stat, err := statFromDB(mb.Config().Stats.DBPath, "user", "tester")
|
stat, err := statFromDB(mb.Config().Stats.DBPath, day, "user", "tester")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
actual := stat.val
|
actual := stat.val
|
||||||
assert.Equal(t, actual, expected)
|
assert.Equal(t, actual, expected)
|
||||||
|
@ -221,6 +211,7 @@ func TestMessages(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestChannelCounter", func(t *testing.T) {
|
t.Run("TestChannelCounter", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
count := 5
|
count := 5
|
||||||
expected := value(count)
|
expected := value(count)
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
|
@ -235,7 +226,7 @@ func TestMessages(t *testing.T) {
|
||||||
_, err := os.Stat(dbPath)
|
_, err := os.Stat(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
stat, err := statFromDB(mb.Config().Stats.DBPath, "channel", "test")
|
stat, err := statFromDB(mb.Config().Stats.DBPath, day, "channel", "test")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
actual := stat.val
|
actual := stat.val
|
||||||
assert.Equal(t, actual, expected)
|
assert.Equal(t, actual, expected)
|
||||||
|
@ -244,6 +235,7 @@ func TestMessages(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestSightingCounter", func(t *testing.T) {
|
t.Run("TestSightingCounter", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
count := 5
|
count := 5
|
||||||
expected := value(count)
|
expected := value(count)
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
|
@ -261,7 +253,7 @@ func TestMessages(t *testing.T) {
|
||||||
_, err := os.Stat(dbPath)
|
_, err := os.Stat(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
stat, err := statFromDB(mb.Config().Stats.DBPath, "sighting", "user")
|
stat, err := statFromDB(mb.Config().Stats.DBPath, day, "sighting", "user")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
actual := stat.val
|
actual := stat.val
|
||||||
assert.Equal(t, actual, expected)
|
assert.Equal(t, actual, expected)
|
||||||
|
@ -270,6 +262,7 @@ func TestMessages(t *testing.T) {
|
||||||
rmDB(t)
|
rmDB(t)
|
||||||
|
|
||||||
t.Run("TestSightingCounterNoResults", func(t *testing.T) {
|
t.Run("TestSightingCounterNoResults", func(t *testing.T) {
|
||||||
|
day := mkDay()
|
||||||
count := 5
|
count := 5
|
||||||
expected := value(0)
|
expected := value(0)
|
||||||
mb := bot.NewMockBot()
|
mb := bot.NewMockBot()
|
||||||
|
@ -287,7 +280,7 @@ func TestMessages(t *testing.T) {
|
||||||
_, err := os.Stat(dbPath)
|
_, err := os.Stat(dbPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
stat, err := statFromDB(mb.Config().Stats.DBPath, "sighting", "user")
|
stat, err := statFromDB(mb.Config().Stats.DBPath, day, "sighting", "user")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
actual := stat.val
|
actual := stat.val
|
||||||
assert.Equal(t, actual, expected)
|
assert.Equal(t, actual, expected)
|
||||||
|
|
Loading…
Reference in New Issue