From 2513c2bc5a998227b38a3f5e85840ddf6c9f452b Mon Sep 17 00:00:00 2001 From: Ash Keel Date: Sun, 6 Jun 2021 01:18:31 +0200 Subject: [PATCH] Fix mutex deadlock --- main.go | 2 ++ modules/loyalty/manager.go | 12 ++++++------ modules/twitch/bot.go | 13 ++++++++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 4ca71ee..04d4dfa 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,8 @@ import ( "github.com/mattn/go-colorable" "github.com/sirupsen/logrus" + + _ "net/http/pprof" ) const AppTitle = "strimertül" diff --git a/modules/loyalty/manager.go b/modules/loyalty/manager.go index e36bf5c..c8bbdf5 100644 --- a/modules/loyalty/manager.go +++ b/modules/loyalty/manager.go @@ -108,20 +108,20 @@ func (m *Manager) update(kvs []database.ModifiedKV) error { switch key { case ConfigKey: m.mu.Lock() - defer m.mu.Unlock() err = jsoniter.ConfigFastest.Unmarshal(kv.Data, &m.config) + m.mu.Unlock() case GoalsKey: m.mu.Lock() - defer m.mu.Unlock() err = jsoniter.ConfigFastest.Unmarshal(kv.Data, &m.goals) + m.mu.Unlock() case RewardsKey: m.mu.Lock() - defer m.mu.Unlock() err = jsoniter.ConfigFastest.Unmarshal(kv.Data, &m.rewards) + m.mu.Unlock() case QueueKey: m.mu.Lock() - defer m.mu.Unlock() err = jsoniter.ConfigFastest.Unmarshal(kv.Data, &m.queue) + m.mu.Unlock() case CreateRedeemRPC: var redeem Redeem err = jsoniter.ConfigFastest.Unmarshal(kv.Data, &redeem) @@ -139,12 +139,12 @@ func (m *Manager) update(kvs []database.ModifiedKV) error { switch { // User point changed case strings.HasPrefix(kv.Key, PointsPrefix): - m.mu.Lock() - defer m.mu.Unlock() var entry PointsEntry err = jsoniter.ConfigFastest.Unmarshal(kv.Data, &entry) user := kv.Key[len(PointsPrefix):] + m.mu.Lock() m.points[user] = entry + m.mu.Unlock() } } if err != nil { diff --git a/modules/twitch/bot.go b/modules/twitch/bot.go index 36ef85e..9ecacd5 100644 --- a/modules/twitch/bot.go +++ b/modules/twitch/bot.go @@ -2,6 +2,7 @@ package twitch import ( "strings" + "sync" "time" irc "github.com/gempir/go-twitch-irc/v2" @@ -21,6 +22,8 @@ type Bot struct { activeUsers map[string]bool banlist map[string]bool + mu sync.Mutex + // Module specific vars Loyalty *loyalty.Manager } @@ -38,6 +41,7 @@ func NewBot(api *Client, config BotConfig) *Bot { lastMessage: time.Now(), activeUsers: make(map[string]bool), banlist: make(map[string]bool), + mu: sync.Mutex{}, } client.OnPrivateMessage(func(message irc.PrivateMessage) { @@ -47,14 +51,16 @@ func NewBot(api *Client, config BotConfig) *Bot { bot.logger.Debug("message received too soon, ignoring") return } + bot.mu.Lock() bot.activeUsers[message.User.Name] = true + bot.mu.Unlock() // Check if it's a command if strings.HasPrefix(message.Message, "!") { // Run through supported commands for cmd, data := range commands { if strings.HasPrefix(message.Message, cmd) { - data.Handler(bot, message) + go data.Handler(bot, message) bot.lastMessage = time.Now() } } @@ -71,6 +77,7 @@ func NewBot(api *Client, config BotConfig) *Bot { }).Debug("user joined channel") } }) + client.OnUserPartMessage(func(message irc.UserPartMessage) { if strings.ToLower(message.User) == bot.username { bot.logger.WithField("channel", message.Channel).Info("left channel") @@ -168,11 +175,15 @@ func (b *Bot) IsBanned(user string) bool { } func (b *Bot) IsActive(user string) bool { + b.mu.Lock() + defer b.mu.Unlock() active, ok := b.activeUsers[user] return ok && active } func (b *Bot) ResetActivity() { + b.mu.Lock() + defer b.mu.Unlock() b.activeUsers = make(map[string]bool) }