package db import ( "sync" "time" ) type CooldownEntry struct { UserID string QuestionID string } type Cooldowns struct { m map[CooldownEntry]time.Time mu *sync.Mutex } func NewCooldowns() Cooldowns { c := make(map[CooldownEntry]time.Time) mu := &sync.Mutex{} go func() { for { mu.Lock() now := time.Now() for k, v := range c { if now.After(v) { delete(c, k) } } mu.Unlock() time.Sleep(time.Minute * 5) } }() return Cooldowns{c, mu} } func (c Cooldowns) NewAttempt(userID string, questionID string, attempts int) { c.mu.Lock() defer c.mu.Unlock() var timeout time.Duration switch attempts { case 0: timeout = time.Minute case 1: timeout = time.Minute * 3 / 2 // 90 seconds case 2: timeout = time.Minute * 3 default: timeout = time.Minute * 5 } c.m[CooldownEntry{userID, questionID}] = time.Now().Add(timeout) } func (c Cooldowns) Check(userID string, questionID string) time.Duration { c.mu.Lock() defer c.mu.Unlock() expires, ok := c.m[CooldownEntry{userID, questionID}] now := time.Now() if !ok || now.After(expires) { return 0 } return expires.Sub(now) }