diff --git a/actions.go b/actions.go index f08596b..6187f6b 100644 --- a/actions.go +++ b/actions.go @@ -44,6 +44,6 @@ func handleMessage(c *irc.Client, m *irc.Message, event *string) { } // Lock command - timerStore.Add(r.MatcherID()) + timerStore.AddCooldown(r.MatcherID()) } } diff --git a/config.go b/config.go index b3f4454..66a50ee 100644 --- a/config.go +++ b/config.go @@ -167,7 +167,7 @@ func (r *rule) Matches(m *irc.Message, event *string) bool { } // Check whether rule is in cooldown - if r.Cooldown != nil && timerStore.Has(r.MatcherID(), *r.Cooldown) { + if r.Cooldown != nil && timerStore.InCooldown(r.MatcherID(), *r.Cooldown) { logger.Trace("Non-Match: On cooldown") return false } diff --git a/timers.go b/timers.go index 85d228c..615865b 100644 --- a/timers.go +++ b/timers.go @@ -8,48 +8,78 @@ import ( "time" ) +type timerType uint8 + +const ( + timerTypePermit timerType = iota + timerTypeChatMessage + timerTypeCooldown +) + var timerStore = newTimer() +type timerEntry struct { + kind timerType + time time.Time +} + type timer struct { - timers map[string]time.Time + timers map[string]timerEntry lock *sync.RWMutex + kind timerType } func newTimer() *timer { return &timer{ - timers: map[string]time.Time{}, + timers: map[string]timerEntry{}, lock: new(sync.RWMutex), } } -func (t *timer) Add(id string) { - t.lock.Lock() - defer t.lock.Unlock() +// Cooldown timer - t.timers[id] = time.Now() +func (t *timer) AddCooldown(ruleID string) { + t.add(timerTypeCooldown, t.getCooldownTimerKey(ruleID)) } +func (t *timer) InCooldown(ruleID string, cooldown time.Duration) bool { + return t.has(t.getCooldownTimerKey(ruleID), cooldown) +} + +func (t timer) getCooldownTimerKey(ruleID string) string { + h := sha256.New() + fmt.Fprintf(h, "%d:%s", timerTypeCooldown, ruleID) + return fmt.Sprintf("sha256:%x", h.Sum(nil)) +} + +// Permit timer + func (t *timer) AddPermit(channel, username string) { - t.Add(t.getPermitTimerKey(channel, username)) -} - -func (t *timer) Has(id string, validity time.Duration) bool { - t.lock.RLock() - defer t.lock.RUnlock() - - return time.Since(t.timers[id]) < validity + t.add(timerTypePermit, t.getPermitTimerKey(channel, username)) } func (t *timer) HasPermit(channel, username string) bool { - return t.Has(t.getPermitTimerKey(channel, username), config.PermitTimeout) -} - -func (t timer) NormalizeUsername(username string) string { - return strings.ToLower(strings.TrimLeft(username, "@")) + return t.has(t.getPermitTimerKey(channel, username), config.PermitTimeout) } func (t timer) getPermitTimerKey(channel, username string) string { h := sha256.New() - fmt.Fprintf(h, "%s:%s", channel, t.NormalizeUsername(username)) + fmt.Fprintf(h, "%d:%s:%s", timerTypePermit, channel, strings.ToLower(strings.TrimLeft(username, "@"))) return fmt.Sprintf("sha256:%x", h.Sum(nil)) } + +// Generic + +func (t *timer) add(kind timerType, id string) { + t.lock.Lock() + defer t.lock.Unlock() + + t.timers[id] = timerEntry{kind: kind, time: time.Now()} +} + +func (t *timer) has(id string, validity time.Duration) bool { + t.lock.RLock() + defer t.lock.RUnlock() + + return time.Since(t.timers[id].time) < validity +}