rate_limiter_engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/rate_limiter.rb +6 -0
- data/lib/rate_limiter/configuration.rb +20 -0
- data/lib/rate_limiter/engine.rb +5 -0
- data/lib/rate_limiter/rate_limit.rb +45 -0
- data/lib/rate_limiter/rate_limiter.rb +70 -0
- data/lib/rate_limiter/version.rb +3 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 25680fbf29d02bc0d1657d03a82074f66608db7115efa20387bb3d613a382d79
|
4
|
+
data.tar.gz: 39d2fe46ef92d55517bf070286157152888a2f3b654215f89a9d57fe0320b047
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0ecd532d39f1d09de8db9f500a6b3e5ee03edfd7b801392cb996dce0f13e20085cfd9354b28f1454715ef5cf9563f66e27f2beffb3ddddc82e13e0d8a65c8bcd
|
7
|
+
data.tar.gz: 701c10ba0dee7ac5a9bdafaa7d79c2f013d59eab9035fadb92a73a9481c9d33394c45438e9b6bb0212d4e3685da94b22ca13cf8b2ae43e0cee3e2a42f203d2cd
|
data/lib/rate_limiter.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module RateLimiter
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :rate_default,
|
4
|
+
:period_default,
|
5
|
+
:force_rate_limit,
|
6
|
+
:force_period
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def configure
|
11
|
+
yield(configuration)
|
12
|
+
|
13
|
+
configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def configuration
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RateLimiter
|
2
|
+
module RateLimit
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
@@rate = {}
|
6
|
+
@@rate_default = ::RateLimiter.configuration.rate_default || 100
|
7
|
+
@@period = {}
|
8
|
+
@@period_default = ::RateLimiter.configuration.period_default || 100
|
9
|
+
|
10
|
+
included do
|
11
|
+
before_action :rate_limiter
|
12
|
+
|
13
|
+
def self.rate(rate)
|
14
|
+
@@rate[controller_name] = rate
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.period(period)
|
18
|
+
@@period[controller_name] = period
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def rate_limiter
|
25
|
+
rate_limiter_object.count
|
26
|
+
rate_limiter_object.increment
|
27
|
+
|
28
|
+
render_limit_exceeded if rate_limiter_object.blocked?
|
29
|
+
end
|
30
|
+
|
31
|
+
def render_limit_exceeded
|
32
|
+
render json: {
|
33
|
+
message: "Rate limit exceeded. Try again in #{rate_limiter_object.cooldown_period} seconds"
|
34
|
+
}, status: :too_many_requests
|
35
|
+
end
|
36
|
+
|
37
|
+
def client_key
|
38
|
+
"#{request.env['REMOTE_IP']}_counter"
|
39
|
+
end
|
40
|
+
|
41
|
+
def rate_limiter_object
|
42
|
+
RateLimiter.new(client_key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module RateLimiter
|
2
|
+
class RateLimiter
|
3
|
+
def initialize(client_key)
|
4
|
+
@client_key = client_key
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :client_key
|
8
|
+
|
9
|
+
def blocked?
|
10
|
+
counter.present? && limit_exceeded
|
11
|
+
end
|
12
|
+
|
13
|
+
def count
|
14
|
+
return if counter
|
15
|
+
|
16
|
+
set_client_key
|
17
|
+
set_expire
|
18
|
+
end
|
19
|
+
|
20
|
+
def increment
|
21
|
+
$redis.incr(client_key)
|
22
|
+
end
|
23
|
+
|
24
|
+
def cooldown_period
|
25
|
+
$redis.ttl(client_key)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def counter
|
31
|
+
$redis.get(client_key)
|
32
|
+
end
|
33
|
+
|
34
|
+
def limit_exceeded
|
35
|
+
counter.to_i > rate_limit.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_client_key
|
39
|
+
$redis.set(client_key, 0)
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_expire
|
43
|
+
$redis.expire(client_key, period)
|
44
|
+
end
|
45
|
+
|
46
|
+
def rate_limit
|
47
|
+
force_rate_limit || rate_default
|
48
|
+
end
|
49
|
+
|
50
|
+
def period
|
51
|
+
force_period || period_default
|
52
|
+
end
|
53
|
+
|
54
|
+
def force_rate_limit
|
55
|
+
::RateLimiter.configuration.force_rate_limit
|
56
|
+
end
|
57
|
+
|
58
|
+
def rate_default
|
59
|
+
::RateLimiter.configuration.rate_default
|
60
|
+
end
|
61
|
+
|
62
|
+
def force_period
|
63
|
+
::RateLimiter.configuration.force_period
|
64
|
+
end
|
65
|
+
|
66
|
+
def period_default
|
67
|
+
::RateLimiter.configuration.period_default
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rate_limiter_engine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vitor Oliveira
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 6.1.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 6.1.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mock_redis
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pg
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Rate Limiter for Rails APIs
|
84
|
+
email:
|
85
|
+
- vbrazo@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- lib/rate_limiter.rb
|
91
|
+
- lib/rate_limiter/configuration.rb
|
92
|
+
- lib/rate_limiter/engine.rb
|
93
|
+
- lib/rate_limiter/rate_limit.rb
|
94
|
+
- lib/rate_limiter/rate_limiter.rb
|
95
|
+
- lib/rate_limiter/version.rb
|
96
|
+
homepage:
|
97
|
+
licenses: []
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubygems_version: 3.1.2
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Rate Limiter for Rails APIs
|
118
|
+
test_files: []
|