rails_rate_limiter 0.1.0 → 0.1.1
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db2890d6018db0c943f902630dc6eddadef419e9
|
4
|
+
data.tar.gz: 5c43ec7b72b33a5472689063ca9bf7832996af93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3df66eb7f88bc89a555e9fa728283c4bf208f3a4fc565bde4d85b309736f4cb31d748d56b98c3ddeff69567f04e66f50383336b00e2772466fdf72ddb76bf046
|
7
|
+
data.tar.gz: 90ed942eaff1ef6f96b450604bef48afe3acc3389173cb7496745353c450005f1338bf84bcb47746d483a1107e68a9f8f0d4e4babac5c47c0e2dd82d5ef24068
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# RailsRateLimiter
|
2
2
|
|
3
|
-
This is a high level rate limiting gem for Ruby on Rails using Redis. It limits amount of requests on
|
3
|
+
This is a high level rate limiting gem for Ruby on Rails using Redis. It limits amount of requests on controller's level, that allows you to customize rate limiting options using everything that available in your action, e.g. `current_user`.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -26,6 +26,8 @@ Add `include RateLimiter` to the controller you want to rate limit. It allows yo
|
|
26
26
|
|
27
27
|
```ruby
|
28
28
|
class Posts < ApplicationController
|
29
|
+
include RailsRateLimiter
|
30
|
+
|
29
31
|
rate_limit limit: 100, per: 1.hour, only: :index do |info|
|
30
32
|
render plain: I18n.t('rate_limit_exceeded', seconds: info.time_left),
|
31
33
|
status: :too_many_requests
|
@@ -65,7 +67,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
65
67
|
|
66
68
|
## Contributing
|
67
69
|
|
68
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
70
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rkotov93/rails_rate_limiter.
|
69
71
|
|
70
72
|
## License
|
71
73
|
|
data/lib/rails_rate_limiter.rb
CHANGED
@@ -5,40 +5,37 @@ require 'rails_rate_limiter/version'
|
|
5
5
|
require 'rails_rate_limiter/strategies'
|
6
6
|
require 'rails_rate_limiter/error'
|
7
7
|
|
8
|
+
# Provides `rate_limit` callback to limit amount of requests
|
9
|
+
# and handle rate limit exceeding
|
8
10
|
module RailsRateLimiter
|
9
11
|
extend ActiveSupport::Concern
|
10
12
|
|
11
13
|
class_methods do
|
12
|
-
# Sets callback that
|
14
|
+
# Sets callback that handles rate limit exceeding. Additionally to
|
15
|
+
# described options supports all the `before_action` options.
|
13
16
|
#
|
14
|
-
#
|
17
|
+
# @example Renders text with time left in case of rate limit exceeding.
|
18
|
+
# rate_limit limit: 100, per: 1.hour, only: :index do |info|
|
19
|
+
# render plain: "Next request can be done in #{info.time_left} seconds",
|
20
|
+
# status: :too_many_requests
|
21
|
+
# end
|
15
22
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# +pattern+ - lambda or proc. Can be used if you want to use something
|
29
|
-
# instead of IP as cache key identifier. For example
|
30
|
-
# `->current_user.id`. Uses `request.remote_ip` by default.
|
31
|
-
# +client+ - Redis client. Uses `Redis.new` by default.
|
32
|
-
#
|
33
|
-
# Any option avaiable for `before_action` can be used.
|
34
|
-
#
|
35
|
-
# == Examples:
|
36
|
-
#
|
37
|
-
# rate_limit limit: 100, per: 1.hour, only: :index do |info|
|
38
|
-
# render plain: I18n.t('rate_limit_exceeded', seconds: info.time_left),
|
39
|
-
# status: :too_many_requests
|
40
|
-
# end
|
23
|
+
# @param [Hash] options
|
24
|
+
# @option options [Symbol] :strategy Rate limiting strategy.
|
25
|
+
# Default value is :sliding_window_log
|
26
|
+
# @option options [Fixnum, Lambda, Proc] :limit The number of allowed
|
27
|
+
# requests per time period. Default value is 100
|
28
|
+
# @option options [Fixnum, Lambda, Proc] :per Time period in seconds.
|
29
|
+
# Default value is 1.hour
|
30
|
+
# @option options [Lambda, Proc] :pattern Can be used if you want to use
|
31
|
+
# something instead of IP as cache key identifier. For example
|
32
|
+
# `-> { current_user.id }`. Default value is `request.remote_ip`
|
33
|
+
# @option options [Object] :cient Redis client.
|
34
|
+
# Uses `Redis.new` if not specified
|
41
35
|
#
|
36
|
+
# @yield [info] Executed if rate limit exceded. This argument is mandatory.
|
37
|
+
# @yieldparam [RailsRateLimiter::Result] Represent information about
|
38
|
+
# rate limiting
|
42
39
|
def rate_limit(options = {}, &block)
|
43
40
|
raise Error, 'Handling block was not provided' unless block_given?
|
44
41
|
|
@@ -8,6 +8,11 @@ module RailsRateLimiter
|
|
8
8
|
|
9
9
|
attr_reader :limit, :expires_in, :requester_pattern
|
10
10
|
|
11
|
+
# @param limit [Fixnum, Lambda, Proc] The number of allowed
|
12
|
+
# requests per time period.
|
13
|
+
# @param per [Fixnum, Lambda, Proc] :per Time period in seconds.
|
14
|
+
# @param requester [Lambda, Proc] Identifies request
|
15
|
+
# @param client [Object] Redis client
|
11
16
|
def initialize(limit, per, requester, client = nil)
|
12
17
|
@limit = limit.respond_to?(:call) ? limit.call : limit
|
13
18
|
@expires_in = calculate_expires_in(per)
|
@@ -28,11 +33,13 @@ module RailsRateLimiter
|
|
28
33
|
@client ||= Redis.new
|
29
34
|
end
|
30
35
|
|
36
|
+
# Removes all SORTED SET members that have a score < current_timestamp
|
31
37
|
def remove_expired_set_members
|
32
|
-
# remove all SORTED SET members that have a score < current_timestamp
|
33
38
|
client.zremrangebyscore(cache_key, '-inf', "(#{current_timestamp}")
|
34
39
|
end
|
35
40
|
|
41
|
+
# Adds requests to SORTED SET with expiring_timestamp
|
42
|
+
# and current_timestamp
|
36
43
|
def log_request
|
37
44
|
expiring_timestamp = current_timestamp + expires_in
|
38
45
|
client.zadd(cache_key, expiring_timestamp, current_timestamp)
|