mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-12-20 20:01:17 +00:00
[counter] Record first seen and last updated on counters
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
b131a7be5f
commit
94b040ed81
3 changed files with 30 additions and 15 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -193,7 +194,7 @@ func Register(args plugins.RegistrationArguments) (err error) {
|
||||||
mod = val[0]
|
mod = val[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := updateCounter(db, name, mod, false); err != nil {
|
if err := updateCounter(db, name, mod, false, time.Now()); err != nil {
|
||||||
return 0, errors.Wrap(err, "updating counter")
|
return 0, errors.Wrap(err, "updating counter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +231,7 @@ func (actorCounter) Execute(_ *irc.Client, m *irc.Message, r *plugins.Rule, even
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, errors.Wrap(
|
return false, errors.Wrap(
|
||||||
updateCounter(db, counterName, counterValue, true),
|
updateCounter(db, counterName, counterValue, true, time.Now()),
|
||||||
"set counter",
|
"set counter",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -249,7 +250,7 @@ func (actorCounter) Execute(_ *irc.Client, m *irc.Message, r *plugins.Rule, even
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, errors.Wrap(
|
return false, errors.Wrap(
|
||||||
updateCounter(db, counterName, counterStep, false),
|
updateCounter(db, counterName, counterStep, false, time.Now()),
|
||||||
"update counter",
|
"update counter",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -298,7 +299,7 @@ func routeActorCounterSetValue(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = updateCounter(db, mux.Vars(r)["name"], value, absolute); err != nil {
|
if err = updateCounter(db, mux.Vars(r)["name"], value, absolute, time.Now()); err != nil {
|
||||||
http.Error(w, errors.Wrap(err, "updating value").Error(), http.StatusInternalServerError)
|
http.Error(w, errors.Wrap(err, "updating value").Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package counter
|
package counter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
|
@ -13,6 +15,8 @@ type (
|
||||||
counter struct {
|
counter struct {
|
||||||
Name string `gorm:"primaryKey"`
|
Name string `gorm:"primaryKey"`
|
||||||
Value int64
|
Value int64
|
||||||
|
FirstSeen time.Time
|
||||||
|
LastModified time.Time
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,7 +36,7 @@ func getCounterValue(db database.Connector, counterName string) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//revive:disable-next-line:flag-parameter
|
//revive:disable-next-line:flag-parameter
|
||||||
func updateCounter(db database.Connector, counterName string, value int64, absolute bool) error {
|
func updateCounter(db database.Connector, counterName string, value int64, absolute bool, atTime time.Time) error {
|
||||||
if !absolute {
|
if !absolute {
|
||||||
cv, err := getCounterValue(db, counterName)
|
cv, err := getCounterValue(db, counterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,8 +50,8 @@ func updateCounter(db database.Connector, counterName string, value int64, absol
|
||||||
helpers.RetryTransaction(db.DB(), func(tx *gorm.DB) error {
|
helpers.RetryTransaction(db.DB(), func(tx *gorm.DB) error {
|
||||||
return tx.Clauses(clause.OnConflict{
|
return tx.Clauses(clause.OnConflict{
|
||||||
Columns: []clause.Column{{Name: "name"}},
|
Columns: []clause.Column{{Name: "name"}},
|
||||||
DoUpdates: clause.AssignmentColumns([]string{"value"}),
|
DoUpdates: clause.AssignmentColumns([]string{"last_modified", "value"}),
|
||||||
}).Create(counter{Name: counterName, Value: value}).Error
|
}).Create(counter{Name: counterName, Value: value, FirstSeen: atTime.UTC(), LastModified: atTime.UTC()}).Error
|
||||||
}),
|
}),
|
||||||
"storing counter value",
|
"storing counter value",
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package counter
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -20,12 +21,19 @@ func TestCounterStoreLoop(t *testing.T) {
|
||||||
assert.NoError(t, err, "reading non-existent counter")
|
assert.NoError(t, err, "reading non-existent counter")
|
||||||
assert.Equal(t, int64(0), v, "expecting 0 counter value on non-existent counter")
|
assert.Equal(t, int64(0), v, "expecting 0 counter value on non-existent counter")
|
||||||
|
|
||||||
err = updateCounter(dbc, counterName, 5, true)
|
err = updateCounter(dbc, counterName, 5, true, time.Now())
|
||||||
assert.NoError(t, err, "inserting counter")
|
assert.NoError(t, err, "inserting counter")
|
||||||
|
|
||||||
err = updateCounter(dbc, counterName, 1, false)
|
var rawCounter counter
|
||||||
|
assert.NoError(t, dbc.DB().First(&rawCounter, "name = ?", counterName).Error)
|
||||||
|
assert.Equal(t, rawCounter.FirstSeen, rawCounter.LastModified)
|
||||||
|
|
||||||
|
err = updateCounter(dbc, counterName, 1, false, time.Now())
|
||||||
assert.NoError(t, err, "updating counter")
|
assert.NoError(t, err, "updating counter")
|
||||||
|
|
||||||
|
assert.NoError(t, dbc.DB().First(&rawCounter, "name = ?", counterName).Error)
|
||||||
|
assert.NotEqual(t, rawCounter.FirstSeen, rawCounter.LastModified)
|
||||||
|
|
||||||
v, err = getCounterValue(dbc, counterName)
|
v, err = getCounterValue(dbc, counterName)
|
||||||
assert.NoError(t, err, "reading existent counter")
|
assert.NoError(t, err, "reading existent counter")
|
||||||
assert.Equal(t, int64(6), v, "expecting counter value on existing counter")
|
assert.Equal(t, int64(6), v, "expecting counter value on existing counter")
|
||||||
|
@ -35,11 +43,13 @@ func TestCounterTopListAndRank(t *testing.T) {
|
||||||
dbc := database.GetTestDatabase(t)
|
dbc := database.GetTestDatabase(t)
|
||||||
require.NoError(t, dbc.DB().AutoMigrate(&counter{}))
|
require.NoError(t, dbc.DB().AutoMigrate(&counter{}))
|
||||||
|
|
||||||
|
testTime := time.Now().UTC()
|
||||||
|
|
||||||
counterTemplate := `#example:test:%v`
|
counterTemplate := `#example:test:%v`
|
||||||
for i := 0; i < 6; i++ {
|
for i := 0; i < 6; i++ {
|
||||||
require.NoError(
|
require.NoError(
|
||||||
t,
|
t,
|
||||||
updateCounter(dbc, fmt.Sprintf(counterTemplate, i), int64(i), true),
|
updateCounter(dbc, fmt.Sprintf(counterTemplate, i), int64(i), true, testTime),
|
||||||
"inserting counter %d", i,
|
"inserting counter %d", i,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -49,9 +59,9 @@ func TestCounterTopListAndRank(t *testing.T) {
|
||||||
assert.Len(t, cc, 3)
|
assert.Len(t, cc, 3)
|
||||||
|
|
||||||
assert.Equal(t, []counter{
|
assert.Equal(t, []counter{
|
||||||
{Name: "#example:test:5", Value: 5},
|
{Name: "#example:test:5", Value: 5, FirstSeen: testTime, LastModified: testTime},
|
||||||
{Name: "#example:test:4", Value: 4},
|
{Name: "#example:test:4", Value: 4, FirstSeen: testTime, LastModified: testTime},
|
||||||
{Name: "#example:test:3", Value: 3},
|
{Name: "#example:test:3", Value: 3, FirstSeen: testTime, LastModified: testTime},
|
||||||
}, cc)
|
}, cc)
|
||||||
|
|
||||||
rank, count, err := getCounterRank(dbc,
|
rank, count, err := getCounterRank(dbc,
|
||||||
|
|
Loading…
Reference in a new issue