From a724a3c62bca11f033e4d6d8bbc7cead4b0f97af Mon Sep 17 00:00:00 2001 From: Roman Kredentser Date: Thu, 1 Apr 2021 14:00:00 +0300 Subject: [PATCH] change after @shamil cr --- algorithm/gcra/gcra_lua.go | 64 -------------------------------------- algorithm/model.go | 15 +-------- limit.go | 14 ++++----- limiter.go | 29 +++++++---------- 4 files changed, 18 insertions(+), 104 deletions(-) delete mode 100644 algorithm/gcra/gcra_lua.go diff --git a/algorithm/gcra/gcra_lua.go b/algorithm/gcra/gcra_lua.go deleted file mode 100644 index 7214468..0000000 --- a/algorithm/gcra/gcra_lua.go +++ /dev/null @@ -1,64 +0,0 @@ -package gcra - -import "github.com/go-redis/redis/v8" - -// Copyright (c) 2017 Pavel Pravosud -// https://github.com/rwz/redis-gcra/blob/master/vendor/perform_gcra_ratelimit.lua -var script = redis.NewScript(` --- this script has side-effects, so it requires replicate commands mode -redis.replicate_commands() - -local rate_limit_key = KEYS[1] -local burst = ARGV[1] -local rate = ARGV[2] -local period = ARGV[3] -local cost = ARGV[4] - -local emission_interval = period / rate -local increment = emission_interval * cost -local burst_offset = emission_interval * burst -local now = redis.call("TIME") - --- redis returns time as an array containing two integers: seconds of the epoch --- time (10 digits) and microseconds (6 digits). for convenience we need to --- convert them to a floating point number. the resulting number is 16 digits, --- bordering on the limits of a 64-bit double-precision floating point number. --- adjust the epoch to be relative to Jan 1, 2017 00:00:00 GMT to avoid floating --- point problems. this approach is good until "now" is 2,483,228,799 (Wed, 09 --- Sep 2048 01:46:39 GMT), when the adjusted value is 16 digits. -local jan_1_2017 = 1483228800 -now = (now[1] - jan_1_2017) + (now[2] / 1000000) - -local tat = redis.call("GET", rate_limit_key) - -if not tat then - tat = now -else - tat = tonumber(tat) -end - -local new_tat = math.max(tat, now) + increment - -local allow_at = new_tat - burst_offset -local diff = now - allow_at - -local limited -local retry_after -local reset_after - -local remaining = math.floor(diff / emission_interval + 0.5) -- poor man's round - -if remaining < 0 then - limited = 1 - remaining = 0 - reset_after = tat - now - retry_after = diff * -1 -else - limited = 0 - reset_after = new_tat - now - redis.call("SET", rate_limit_key, new_tat, "EX", math.ceil(reset_after)) - retry_after = -1 -end - -return {limited, remaining, tostring(retry_after), tostring(reset_after)} -`) diff --git a/algorithm/model.go b/algorithm/model.go index ef6064d..39c90c3 100644 --- a/algorithm/model.go +++ b/algorithm/model.go @@ -2,15 +2,12 @@ package algorithm import ( "context" - "fmt" "time" "github.com/go-redis/redis/v8" ) -var ( - Registry []*RegInfo -) +var Registry []*RegInfo type ( Limit interface { @@ -79,13 +76,3 @@ type ( func Register(info *RegInfo) { Registry = append(Registry, info) } - -func Find(name string) (*RegInfo, error) { - for _, item := range Registry { - if item.Name == name { - return item, nil - } - } - - return nil, fmt.Errorf("didn't find algorithm called %q", name) -} diff --git a/limit.go b/limit.go index 813fb98..2743d9b 100644 --- a/limit.go +++ b/limit.go @@ -2,14 +2,12 @@ package go_redis_ratelimit import "time" -type ( - Limit struct { - Algorithm string - Burst int64 - Rate int64 - Period time.Duration - } -) +type Limit struct { + Algorithm string + Burst int64 + Rate int64 + Period time.Duration +} func (l *Limit) GetAlgorithm() string { return l.Algorithm diff --git a/limiter.go b/limiter.go index e2ddadf..baff76f 100644 --- a/limiter.go +++ b/limiter.go @@ -6,38 +6,31 @@ import ( "github.com/go-redis/redis/v8" "github.com/bringg/go_redis_ratelimit/algorithm" - _ "github.com/bringg/go_redis_ratelimit/algorithm/all" ) -const ( - DefaultPrefix = "limiter" -) - -var ( - algorithmPool map[string]algorithm.Algorithm -) +const DefaultPrefix = "limiter" -type ( - // Limiter controls how frequently events are allowed to happen. - Limiter struct { - Prefix string - } -) +// Limiter controls how frequently events are allowed to happen. +type Limiter struct { + Prefix string + algorithms map[string]algorithm.Algorithm +} // NewLimiter returns a new Limiter. func NewLimiter(rdb *redis.Client) (*Limiter, error) { - algorithmPool = make(map[string]algorithm.Algorithm, len(algorithm.Registry)) + algorithms := make(map[string]algorithm.Algorithm, len(algorithm.Registry)) var err error for _, info := range algorithm.Registry { - if algorithmPool[info.Name], err = info.NewAlgorithm(rdb); err != nil { + if algorithms[info.Name], err = info.NewAlgorithm(rdb); err != nil { return nil, err } } return &Limiter{ - Prefix: DefaultPrefix, + Prefix: DefaultPrefix, + algorithms: algorithms, }, nil } @@ -54,7 +47,7 @@ func (l *Limiter) Allow(key string, limit *Limit) (*algorithm.Result, error) { } func (l *Limiter) findAlgorithm(name string) (algorithm.Algorithm, error) { - if algo, ok := algorithmPool[name]; ok { + if algo, ok := l.algorithms[name]; ok { return algo, nil }