-
Notifications
You must be signed in to change notification settings - Fork 921
/
recent_rolemenus.go
118 lines (93 loc) · 2.57 KB
/
recent_rolemenus.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package rolecommands
import (
"sync"
"time"
"github.com/jonas747/yagpdb/bot"
)
type RecentTrackedMenu struct {
t time.Time
MsgID int64
}
// RecentMenusTracker is simply a way to reduce database queries
// We keep a small cache of message id's with menus on them created recently, that way
// we don't need to query the database on all messages with reactions on them if they're created within this tracked time interval
type RecentMenusTracker struct {
RecentMenus []*RecentTrackedMenu
Started time.Time
EvictionAge time.Duration
// If a guild created a menu from another source this gets set to that time
GuildStartTimes map[int64]time.Time
mu sync.RWMutex
}
func NewRecentMenusTracker(evictionTreshold time.Duration) *RecentMenusTracker {
tracker := &RecentMenusTracker{
RecentMenus: make([]*RecentTrackedMenu, 0),
Started: time.Now(),
EvictionAge: evictionTreshold,
GuildStartTimes: make(map[int64]time.Time),
}
go tracker.RunLoop()
return tracker
}
func (r *RecentMenusTracker) AddMenu(msgID int64) {
t := bot.SnowflakeToTime(msgID)
if time.Since(t) > r.EvictionAge {
return
}
r.mu.Lock()
defer r.mu.Unlock()
for _, v := range r.RecentMenus {
if v.MsgID == msgID {
return // Collision
}
}
r.RecentMenus = append(r.RecentMenus, &RecentTrackedMenu{
t: t,
MsgID: msgID,
})
}
func (r *RecentMenusTracker) CheckRecentTrackedMenu(guildID int64, msgID int64) (outOfTimeRange bool, checkDB bool) {
timestamp := bot.SnowflakeToTime(msgID)
if timestamp.Before(r.Started) || time.Since(timestamp) > r.EvictionAge {
return true, true // outside of tracked range, need to check DB
}
r.mu.RLock()
defer r.mu.RUnlock()
if t, ok := r.GuildStartTimes[guildID]; ok {
if timestamp.Before(t) {
return true, true
}
}
for _, v := range r.RecentMenus {
if v.MsgID == msgID {
// there's a menu created on this message
return false, true
}
}
// no need to check db, no menu found here
return false, false
}
func (r *RecentMenusTracker) GuildReset(guildID int64) {
r.mu.Lock()
defer r.mu.Unlock()
r.GuildStartTimes[guildID] = time.Now()
}
func (r *RecentMenusTracker) RunLoop() {
tickInterval := time.Minute
ticker := time.NewTicker(tickInterval)
for {
<-ticker.C
r.loopCheck(time.Now().Add(-(r.EvictionAge + tickInterval)))
}
}
func (r *RecentMenusTracker) loopCheck(treshold time.Time) {
r.mu.Lock()
defer r.mu.Unlock()
newList := make([]*RecentTrackedMenu, 0, len(r.RecentMenus))
for _, v := range r.RecentMenus {
if v.t.After(treshold) {
newList = append(newList, v)
}
}
r.RecentMenus = newList
}