1
0
Fork 0
mirror of https://git.sr.ht/~ashkeel/strimertul synced 2024-09-30 02:40:33 +00:00
strimertul/twitch/timers/module.go

160 lines
3.7 KiB
Go
Raw Normal View History

2024-03-10 16:38:18 +00:00
package timers
import (
2024-03-12 22:39:18 +00:00
"context"
"math/rand"
"time"
2023-11-10 20:36:15 +00:00
"git.sr.ht/~ashkeel/containers/sync"
2024-03-10 16:38:18 +00:00
jsoniter "github.com/json-iterator/go"
2022-01-27 15:49:18 +00:00
"go.uber.org/zap"
2023-11-10 20:36:15 +00:00
"git.sr.ht/~ashkeel/strimertul/database"
2024-03-10 16:38:18 +00:00
"git.sr.ht/~ashkeel/strimertul/twitch/chat"
)
2024-03-10 16:38:18 +00:00
var json = jsoniter.ConfigFastest
const AverageMessageWindow = 5
2024-03-10 16:38:18 +00:00
type Module struct {
Config Config
lastTrigger *sync.Map[string, time.Time]
messages *sync.Slice[int]
2024-03-12 23:50:59 +00:00
logger *zap.Logger
db database.Database
ctx context.Context
}
2024-03-12 22:39:18 +00:00
func Setup(ctx context.Context, db database.Database, logger *zap.Logger) *Module {
2024-03-10 16:38:18 +00:00
mod := &Module{
lastTrigger: sync.NewMap[string, time.Time](),
messages: sync.NewSlice[int](),
2024-03-10 16:38:18 +00:00
db: db,
2024-03-12 22:39:18 +00:00
ctx: ctx,
2024-03-10 16:38:18 +00:00
logger: logger,
2022-12-03 23:04:15 +00:00
}
// Fill messages with zero values
// (This can probably be done faster)
2024-02-25 13:58:35 +00:00
for i := 0; i < AverageMessageWindow; i++ {
2022-12-03 23:04:15 +00:00
mod.messages.Push(0)
}
// Load config from database
2024-03-12 23:50:59 +00:00
if err := db.GetJSON(ConfigKey, &mod.Config); err != nil {
2024-03-10 16:38:18 +00:00
logger.Debug("Config load error", zap.Error(err))
mod.Config = Config{
Timers: make(map[string]ChatTimer),
}
2021-12-06 11:23:04 +00:00
// Save empty config
2024-03-10 16:38:18 +00:00
err = db.PutJSON(ConfigKey, mod.Config)
if err != nil {
2024-03-10 16:38:18 +00:00
logger.Warn("Could not save default config for bot timers", zap.Error(err))
}
}
2024-03-12 23:50:59 +00:00
if err := db.SubscribeKeyContext(ctx, ConfigKey, func(value string) {
if err := json.UnmarshalFromString(value, &mod.Config); err != nil {
logger.Warn("Error reloading timer config", zap.Error(err))
return
2021-11-24 11:43:55 +00:00
}
2024-03-12 23:50:59 +00:00
logger.Info("Reloaded timer config")
}); err != nil {
2024-03-10 16:38:18 +00:00
logger.Error("Could not set-up timer reload subscription", zap.Error(err))
}
2021-11-24 11:43:55 +00:00
2024-03-10 16:38:18 +00:00
logger.Debug("Loaded timers", zap.Int("timers", len(mod.Config.Timers)))
2021-11-05 21:54:42 +00:00
// Start goroutine for clearing message counters and running timers
go mod.runTimers()
return mod
}
2024-03-10 16:38:18 +00:00
func (m *Module) runTimers() {
for {
// Wait until next tick (remainder until next minute, as close to 0 seconds as possible)
currentTime := time.Now()
nextTick := currentTime.Round(time.Minute).Add(time.Minute)
timeUntilNextTick := nextTick.Sub(currentTime)
time.Sleep(timeUntilNextTick)
2024-03-10 16:38:18 +00:00
err := m.db.PutJSON(chat.ActivityKey, m.messages.Get())
if err != nil {
2024-03-10 16:38:18 +00:00
m.logger.Warn("Error saving chat activity", zap.Error(err))
}
// Calculate activity
activity := m.currentChatActivity()
// Reset timer
index := time.Now().Minute() % AverageMessageWindow
messages := m.messages.Get()
messages[index] = 0
m.messages.Set(messages)
// Run timers
for name, timer := range m.Config.Timers {
m.ProcessTimer(name, timer, activity)
}
}
}
2024-03-10 16:38:18 +00:00
func (m *Module) ProcessTimer(name string, timer ChatTimer, activity int) {
// Must be enabled
if !timer.Enabled {
return
}
// Check if enough time has passed
lastTriggeredTime, ok := m.lastTrigger.GetKey(name)
if !ok {
// If it's the first time we're checking it, start the cooldown
lastTriggeredTime = time.Now()
m.lastTrigger.SetKey(name, lastTriggeredTime)
}
minDelay := timer.MinimumDelay
if minDelay < 60 {
minDelay = 60
}
now := time.Now()
if now.Sub(lastTriggeredTime) < time.Duration(minDelay)*time.Second {
return
}
// Make sure chat activity is high enough
if activity < timer.MinimumChatActivity {
return
}
// Pick a random message
message := timer.Messages[rand.Intn(len(timer.Messages))]
// Write message to chat
2024-03-10 16:38:18 +00:00
chat.WriteMessage(m.db, m.logger, chat.WriteMessageRequest{
Message: message,
Announce: timer.Announce,
})
// Update last trigger
m.lastTrigger.SetKey(name, now)
}
2024-03-10 16:38:18 +00:00
func (m *Module) currentChatActivity() int {
total := 0
2022-12-03 16:29:19 +00:00
for _, v := range m.messages.Get() {
total += v
}
return total
}
2024-03-10 16:38:18 +00:00
func (m *Module) OnMessage() {
index := time.Now().Minute() % AverageMessageWindow
2022-12-03 23:04:15 +00:00
m.messages.SetIndex(index, 1)
}