2021-05-16 17:36:53 +01:00
|
|
|
// Copyright (C) 2021 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package contact
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"golang.org/x/time/rate"
|
|
|
|
|
2021-08-12 17:26:43 +01:00
|
|
|
"storj.io/common/lrucache"
|
2021-05-16 17:36:53 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// RateLimiter allows to prevent multiple events in fixed period of time.
|
|
|
|
type RateLimiter struct {
|
|
|
|
limiters *lrucache.ExpiringLRU
|
|
|
|
interval time.Duration // interval during which events are not limiting.
|
|
|
|
burst int // maximum number of events allowed during duration.
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRateLimiter is a constructor for RateLimiter.
|
|
|
|
func NewRateLimiter(interval time.Duration, burst, numLimits int) *RateLimiter {
|
|
|
|
return &RateLimiter{
|
2023-04-04 10:11:06 +01:00
|
|
|
limiters: lrucache.New(lrucache.Options{
|
|
|
|
Expiration: -1,
|
|
|
|
Capacity: numLimits,
|
|
|
|
Name: "contact-ratelimit",
|
|
|
|
}),
|
2021-05-16 17:36:53 +01:00
|
|
|
interval: interval,
|
|
|
|
burst: burst,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsAllowed indicates if event is allowed to happen.
|
|
|
|
func (rateLimiter *RateLimiter) IsAllowed(key string) bool {
|
|
|
|
limiter, err := rateLimiter.limiters.Get(key, func() (interface{}, error) {
|
|
|
|
return rate.NewLimiter(
|
|
|
|
rate.Limit(time.Second)/rate.Limit(rateLimiter.interval),
|
|
|
|
rateLimiter.burst,
|
|
|
|
), nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("unreachable: %+v", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return limiter.(*rate.Limiter).Allow()
|
|
|
|
}
|