2024-07-25 03:04:26 +00:00
|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"golang.org/x/time/rate"
|
|
|
|
)
|
|
|
|
|
|
|
|
type KindLimiter struct {
|
|
|
|
Limiter *rate.Limiter
|
|
|
|
Limit rate.Limit
|
|
|
|
Burst int
|
|
|
|
}
|
|
|
|
|
2024-07-25 13:03:34 +00:00
|
|
|
type CategoryLimiter struct {
|
|
|
|
Limiter *rate.Limiter
|
|
|
|
Limit rate.Limit
|
|
|
|
Burst int
|
|
|
|
}
|
|
|
|
|
2024-07-25 03:04:26 +00:00
|
|
|
type RateLimiter struct {
|
2024-07-25 13:57:24 +00:00
|
|
|
eventLimiter *rate.Limiter
|
|
|
|
wsLimiter *rate.Limiter
|
|
|
|
kindLimiters map[int]*KindLimiter
|
2024-07-25 13:03:34 +00:00
|
|
|
categoryLimiters map[string]*CategoryLimiter
|
2024-07-25 13:57:24 +00:00
|
|
|
mu sync.RWMutex
|
2024-07-25 03:04:26 +00:00
|
|
|
}
|
|
|
|
|
2024-07-25 13:57:24 +00:00
|
|
|
var rateLimiterInstance *RateLimiter
|
|
|
|
var once sync.Once
|
|
|
|
|
2024-07-25 03:04:26 +00:00
|
|
|
func NewRateLimiter(eventLimit rate.Limit, eventBurst int, wsLimit rate.Limit, wsBurst int) *RateLimiter {
|
|
|
|
return &RateLimiter{
|
2024-07-25 13:57:24 +00:00
|
|
|
eventLimiter: rate.NewLimiter(eventLimit, eventBurst),
|
|
|
|
wsLimiter: rate.NewLimiter(wsLimit, wsBurst),
|
|
|
|
kindLimiters: make(map[int]*KindLimiter),
|
2024-07-25 13:03:34 +00:00
|
|
|
categoryLimiters: make(map[string]*CategoryLimiter),
|
2024-07-25 03:04:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rl *RateLimiter) AddKindLimit(kind int, limit rate.Limit, burst int) {
|
|
|
|
rl.mu.Lock()
|
|
|
|
defer rl.mu.Unlock()
|
|
|
|
rl.kindLimiters[kind] = &KindLimiter{
|
|
|
|
Limiter: rate.NewLimiter(limit, burst),
|
|
|
|
Limit: limit,
|
|
|
|
Burst: burst,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-25 13:03:34 +00:00
|
|
|
func (rl *RateLimiter) AddCategoryLimit(category string, limit rate.Limit, burst int) {
|
|
|
|
rl.mu.Lock()
|
|
|
|
defer rl.mu.Unlock()
|
|
|
|
rl.categoryLimiters[category] = &CategoryLimiter{
|
|
|
|
Limiter: rate.NewLimiter(limit, burst),
|
|
|
|
Limit: limit,
|
|
|
|
Burst: burst,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rl *RateLimiter) AllowEvent(kind int, category string) bool {
|
2024-07-25 03:04:26 +00:00
|
|
|
rl.mu.RLock()
|
|
|
|
defer rl.mu.RUnlock()
|
|
|
|
|
|
|
|
if !rl.eventLimiter.Allow() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if kindLimiter, exists := rl.kindLimiters[kind]; exists {
|
|
|
|
if !kindLimiter.Limiter.Allow() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-25 13:03:34 +00:00
|
|
|
if categoryLimiter, exists := rl.categoryLimiters[category]; exists {
|
|
|
|
if !categoryLimiter.Limiter.Allow() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-25 03:04:26 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rl *RateLimiter) AllowWs() bool {
|
|
|
|
return rl.wsLimiter.Allow()
|
|
|
|
}
|
2024-07-25 13:57:24 +00:00
|
|
|
|
|
|
|
func SetRateLimiter(rl *RateLimiter) {
|
|
|
|
once.Do(func() {
|
|
|
|
rateLimiterInstance = rl
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetRateLimiter() *RateLimiter {
|
|
|
|
return rateLimiterInstance
|
|
|
|
}
|