add redis storage for timers

This commit is contained in:
lyx0 2023-04-13 03:26:20 +02:00
parent 79892fed17
commit 39288bfd1c
6 changed files with 100 additions and 13 deletions

View file

@ -1,6 +1,9 @@
BINARY_NAME=Nourybot.out BINARY_NAME=Nourybot.out
BINARY_NAME_API=NourybotApi.out BINARY_NAME_API=NourybotApi.out
cup:
sudo docker compose up
xd: xd:
cd cmd/bot && go build -o ${BINARY_NAME} && ./${BINARY_NAME} -env="dev" cd cmd/bot && go build -o ${BINARY_NAME} && ./${BINARY_NAME} -env="dev"

View file

@ -15,6 +15,7 @@ import (
"github.com/lyx0/nourybot/internal/common" "github.com/lyx0/nourybot/internal/common"
"github.com/lyx0/nourybot/internal/data" "github.com/lyx0/nourybot/internal/data"
"github.com/nicklaw5/helix" "github.com/nicklaw5/helix"
"github.com/redis/go-redis/v9"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -39,9 +40,11 @@ type Application struct {
Db *sql.DB Db *sql.DB
Models data.Models Models data.Models
Scheduler *cron.Cron Scheduler *cron.Cron
Rdb *redis.Client
} }
var envFlag string var envFlag string
var ctx = context.Background()
func init() { func init() {
flag.StringVar(&envFlag, "env", "dev", "database connection to use: (dev/prod)") flag.StringVar(&envFlag, "env", "dev", "database connection to use: (dev/prod)")
@ -115,6 +118,24 @@ func main() {
sugar.Fatal(err) sugar.Fatal(err)
} }
rdb := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "",
DB: 0,
})
err = rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
sugar.Panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
sugar.Panic(err)
}
sugar.Infow("Redis initialization key",
"key", val,
)
// Initialize Application with the new values // Initialize Application with the new values
app := &Application{ app := &Application{
TwitchClient: tc, TwitchClient: tc,
@ -123,6 +144,7 @@ func main() {
Db: db, Db: db,
Models: data.NewModels(db), Models: data.NewModels(db),
Scheduler: cron.New(), Scheduler: cron.New(),
Rdb: rdb,
} }
// Received a PrivateMessage (normal chat message). // Received a PrivateMessage (normal chat message).

View file

@ -8,6 +8,7 @@ import (
"github.com/gempir/go-twitch-irc/v3" "github.com/gempir/go-twitch-irc/v3"
"github.com/lyx0/nourybot/internal/common" "github.com/lyx0/nourybot/internal/common"
"github.com/lyx0/nourybot/internal/data" "github.com/lyx0/nourybot/internal/data"
"github.com/redis/go-redis/v9"
) )
// AddTimer slices the message into relevant parts, adding the values onto a // AddTimer slices the message into relevant parts, adding the values onto a
@ -66,13 +67,28 @@ func (app *Application) AddTimer(name string, message twitch.PrivateMessage) {
} else { } else {
// cronName is the internal, unique tag/name for the timer. // cronName is the internal, unique tag/name for the timer.
// A timer named "sponsor" in channel "forsen" will be named "forsensponsor" // A timer named "sponsor" in channel "forsen" will be named "forsensponsor"
cronName := fmt.Sprintf("%s%s", message.Channel, name) cronName := fmt.Sprintf("%s-%s", message.Channel, name)
app.Scheduler.AddFunc(fmt.Sprintf("@every %s", repeat), func() { app.newPrivateMessageTimer(message.Channel, text) }, cronName) app.Scheduler.AddFunc(fmt.Sprintf("@every %s", repeat), func() { app.newPrivateMessageTimer(message.Channel, text) }, cronName)
app.Logger.Infow("Added new timer", app.Logger.Infow("Added new timer",
"timer", timer, "timer", timer,
) )
if _, err := app.Rdb.Pipelined(ctx, func(rdb redis.Pipeliner) error {
rdb.HSet(ctx, cronName, "timer-name", name)
rdb.HSet(ctx, cronName, "timer-cronname", cronName)
rdb.HSet(ctx, cronName, "timer-text", text)
rdb.HSet(ctx, cronName, "timer-channel", message.Channel)
rdb.HSet(ctx, cronName, "timer-repeat", repeat)
return nil
}); err != nil {
app.Logger.Panic(err)
}
app.Logger.Infow("Loaded timer into redis:",
"key", cronName,
"value", app.Rdb.HGetAll(ctx, cronName),
)
reply := fmt.Sprintf("Successfully added timer %s repeating every %s", name, repeat) reply := fmt.Sprintf("Successfully added timer %s repeating every %s", name, repeat)
common.Send(message.Channel, reply, app.TwitchClient) common.Send(message.Channel, reply, app.TwitchClient)
return return
@ -104,9 +120,10 @@ func (app *Application) EditTimer(name string, message twitch.PrivateMessage) {
} }
// Delete the old timer // Delete the old timer
cronName := fmt.Sprintf("%s%s", message.Channel, name) cronName := fmt.Sprintf("%s-%s", message.Channel, name)
app.Scheduler.RemoveJob(cronName) app.Scheduler.RemoveJob(cronName)
_ = app.Rdb.Del(ctx, cronName)
err = app.Models.Timers.Delete(name) err = app.Models.Timers.Delete(name)
if err != nil { if err != nil {
app.Logger.Errorw("Error deleting timer from database", app.Logger.Errorw("Error deleting timer from database",
@ -174,10 +191,9 @@ func (app *Application) EditTimer(name string, message twitch.PrivateMessage) {
} else { // this is a bit scuffed. The else here is the end of a successful call. } else { // this is a bit scuffed. The else here is the end of a successful call.
// cronName is the internal, unique tag/name for the timer. // cronName is the internal, unique tag/name for the timer.
// A timer named "sponsor" in channel "forsen" will be named "forsensponsor" // A timer named "sponsor" in channel "forsen" will be named "forsensponsor"
cronName := fmt.Sprintf("%s%s", message.Channel, name) cronName := fmt.Sprintf("%s-%s", message.Channel, name)
app.Scheduler.AddFunc(fmt.Sprintf("@every %s", repeat), func() { app.newPrivateMessageTimer(message.Channel, text) }, cronName) app.Scheduler.AddFunc(fmt.Sprintf("@every %s", repeat), func() { app.newPrivateMessageTimer(message.Channel, text) }, cronName)
app.Logger.Infow("Updated a timer", app.Logger.Infow("Updated a timer",
"Name", name, "Name", name,
"Channel", message.Channel, "Channel", message.Channel,
@ -185,6 +201,21 @@ func (app *Application) EditTimer(name string, message twitch.PrivateMessage) {
"New timer", timer, "New timer", timer,
) )
if _, err := app.Rdb.Pipelined(ctx, func(rdb redis.Pipeliner) error {
rdb.HSet(ctx, cronName, "timer-name", name)
rdb.HSet(ctx, cronName, "timer-cronname", cronName)
rdb.HSet(ctx, cronName, "timer-text", text)
rdb.HSet(ctx, cronName, "timer-channel", message.Channel)
rdb.HSet(ctx, cronName, "timer-repeat", repeat)
return nil
}); err != nil {
app.Logger.Panic(err)
}
app.Logger.Infow("Loaded timer into redis:",
"key", cronName,
"value", app.Rdb.HGetAll(ctx, cronName),
)
reply := fmt.Sprintf("Successfully updated timer %s", name) reply := fmt.Sprintf("Successfully updated timer %s", name)
common.Send(message.Channel, reply, app.TwitchClient) common.Send(message.Channel, reply, app.TwitchClient)
return return
@ -222,18 +253,38 @@ func (app *Application) InitialTimers() {
// cronName is the internal, unique tag/name for the timer. // cronName is the internal, unique tag/name for the timer.
// A timer named "sponsor" in channel "forsen" will be named "forsensponsor" // A timer named "sponsor" in channel "forsen" will be named "forsensponsor"
cronName := fmt.Sprintf("%s%s", v.Channel, v.Name) cronName := fmt.Sprintf("%s-%s", v.Channel, v.Name)
// Repeating is at what times the timer should repeat. // Repeating is at what times the timer should repeat.
// 2 minute timer is @every 2m // 2 minute timer is @every 2m
repeating := fmt.Sprintf("@every %s", v.Repeat) repeating := fmt.Sprintf("@every %s", v.Repeat)
if _, err := app.Rdb.Pipelined(ctx, func(rdb redis.Pipeliner) error {
rdb.HSet(ctx, cronName, "timer-id", v.ID)
rdb.HSet(ctx, cronName, "timer-name", v.Name)
rdb.HSet(ctx, cronName, "timer-cronname", cronName)
rdb.HSet(ctx, cronName, "timer-text", v.Text)
rdb.HSet(ctx, cronName, "timer-channel", v.Channel)
rdb.HSet(ctx, cronName, "timer-repeat", v.Repeat)
return nil
}); err != nil {
app.Logger.Panic(err)
}
app.Logger.Infow("Loaded timer into redis:",
"key", cronName,
"value", app.Rdb.HGetAll(ctx, v.Channel),
)
app.Scheduler.AddFunc(repeating, func() { app.newPrivateMessageTimer(v.Channel, v.Text) }, cronName)
// Add new value to the slice // Add new value to the slice
ts = append(ts, v) ts = append(ts, v)
app.Scheduler.AddFunc(repeating, func() { app.newPrivateMessageTimer(v.Channel, v.Text) }, cronName)
} }
// var model1 rdbVal
// if err := app.Rdb.HGetAll(ctx, cronName).Scan(&model1); err != nil {
// app.Logger.Panic(err)
// }
app.Logger.Infow("Initial timers", app.Logger.Infow("Initial timers",
"timer", ts, "timer", ts,
) )
@ -247,7 +298,7 @@ func (app *Application) newPrivateMessageTimer(channel, text string) {
// DeleteTimer takes in the name of a timer and tries to delete the timer from the database. // DeleteTimer takes in the name of a timer and tries to delete the timer from the database.
func (app *Application) DeleteTimer(name string, message twitch.PrivateMessage) { func (app *Application) DeleteTimer(name string, message twitch.PrivateMessage) {
cronName := fmt.Sprintf("%s%s", message.Channel, name) cronName := fmt.Sprintf("%s-%s", message.Channel, name)
app.Scheduler.RemoveJob(cronName) app.Scheduler.RemoveJob(cronName)
app.Logger.Infow("Deleting timer", app.Logger.Infow("Deleting timer",
@ -256,6 +307,7 @@ func (app *Application) DeleteTimer(name string, message twitch.PrivateMessage)
"cronName", cronName, "cronName", cronName,
) )
_ = app.Rdb.Del(ctx, cronName)
err := app.Models.Timers.Delete(name) err := app.Models.Timers.Delete(name)
if err != nil { if err != nil {
app.Logger.Errorw("Error deleting timer from database", app.Logger.Errorw("Error deleting timer from database",

3
go.mod
View file

@ -15,7 +15,10 @@ require (
) )
require ( require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
github.com/redis/go-redis/v9 v9.0.3 // indirect
github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0 // indirect github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect go.uber.org/multierr v1.8.0 // indirect

6
go.sum
View file

@ -2,9 +2,13 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/briandowns/openweathermap v0.18.0 h1:JYTtJ4bKjXZRmDTe7huJ5+dZ7CsjPUw10GUzMASkNV8= github.com/briandowns/openweathermap v0.18.0 h1:JYTtJ4bKjXZRmDTe7huJ5+dZ7CsjPUw10GUzMASkNV8=
github.com/briandowns/openweathermap v0.18.0/go.mod h1:0GLnknqicWxXnGi1IqoOaZIw+kIe5hkt+YM5WY3j8+0= github.com/briandowns/openweathermap v0.18.0/go.mod h1:0GLnknqicWxXnGi1IqoOaZIw+kIe5hkt+YM5WY3j8+0=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/gempir/go-twitch-irc/v3 v3.2.0 h1:ENhsa7RgBE1GMmDqe0iMkvcSYfgw6ZsXilt+sAg32/U= github.com/gempir/go-twitch-irc/v3 v3.2.0 h1:ENhsa7RgBE1GMmDqe0iMkvcSYfgw6ZsXilt+sAg32/U=
@ -28,6 +32,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.0.3 h1:+7mmR26M0IvyLxGZUHxu4GiBkJkVDid0Un+j4ScYu4k=
github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0 h1:cgqwZtnR+IQfUYDLJ3Kiy4aE+O/wExTzEIg8xwC4Qfs= github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0 h1:cgqwZtnR+IQfUYDLJ3Kiy4aE+O/wExTzEIg8xwC4Qfs=
github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0/go.mod h1:n3nudMl178cEvD44PaopxH9jhJaQzthSxUzLO5iKMy4= github.com/shkh/lastfm-go v0.0.0-20191215035245-89a801c244e0/go.mod h1:n3nudMl178cEvD44PaopxH9jhJaQzthSxUzLO5iKMy4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

View file

@ -8,11 +8,12 @@ import (
) )
type Timer struct { type Timer struct {
ID int `json:"id"` ID int `json:"id" redis:"timer-id"`
Name string `json:"name"` Name string `json:"name" redis:"timer-name"`
Text string `json:"text"` CronName string `redis:"timer-cronname"`
Channel string `json:"channel"` Text string `json:"text" redis:"timer-text"`
Repeat string `json:"repeat"` Channel string `json:"channel" redis:"timer-channel"`
Repeat string `json:"repeat" redis:"timer-repeat"`
} }
type TimerModel struct { type TimerModel struct {