lhc 10.4.2 → 10.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1d081bbe01eadc3a60d41068a65bb5b5f5e8d8d44547e8c076b8e0e5f72307d
4
- data.tar.gz: e0c41de69f16e1146aa28227a67cebd278a6f203439bdd737aff1d8247522d2f
3
+ metadata.gz: a016cff9475c03c337aa44f8688b1499e6ea983a63f3d23d65bf638668ad54d8
4
+ data.tar.gz: 061122763aef50722147734b3fe1985427a657b761da635dd3a3e91f82acff52
5
5
  SHA512:
6
- metadata.gz: cfaafff18eea78de74559bc8d866be1d9bcc3666d69bd0ee9ed4eefc8da80b9a962a32e134dc1603299481ab1768f0f44f89b0154652ba2764faa9a08eb29e96
7
- data.tar.gz: 74f4d0d051992fe02bdb31bafa8291b002466981430ad118b89fab189334ff6824864ead2021f86a0c967d7097e3809e75d1ad69e3e83d0f423099929e3b452a
6
+ metadata.gz: 27230061ee806b82ae5f566156460ff179d8b79089dd44fbe5ab493761edf4809165f7f69ff043a99f59a81eb123d603b1644d40116a2682cd4509d32dd6034a
7
+ data.tar.gz: 774fffe78afb5c755b17ec7c04740fd5681a130f4dbe074e19c926d7df863a7948ea6a5b23bc43124238fcb4133029f318547db94f3a5e862bcb8b9f915a7b40
data/README.md CHANGED
@@ -862,6 +862,7 @@ options = {
862
862
  provider: 'local.ch', # name of the provider under which throttling tracking is aggregated,
863
863
  limit: { header: 'Rate-Limit-Limit' }, # either a hard-coded integer, or a hash pointing at the response header containing the limit value
864
864
  remaining: { header: 'Rate-Limit-Remaining' }, # a hash pointing at the response header containing the current amount of remaining requests
865
+ expires: { header: 'Rate-Limit-Reset' } # a hash pointing at the response header containing the timestamp when the quota will reset
865
866
  }
866
867
  }
867
868
 
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
33
33
  s.add_development_dependency 'rspec-rails', '>= 3.0.0'
34
34
  s.add_development_dependency 'rubocop', '~> 0.57.1'
35
35
  s.add_development_dependency 'rubocop-rspec', '~> 1.26.0'
36
+ s.add_development_dependency 'timecop'
36
37
  s.add_development_dependency 'webmock'
37
38
 
38
39
  s.license = 'GPL-3'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/duration'
4
+
3
5
  class LHC::Throttle < LHC::Interceptor
4
6
 
5
7
  class OutOfQuota < StandardError
@@ -24,7 +26,8 @@ class LHC::Throttle < LHC::Interceptor
24
26
  self.class.track ||= {}
25
27
  self.class.track[options.dig(:provider)] = {
26
28
  limit: limit(options: options[:limit], response: response),
27
- remaining: remaining(options: options[:remaining], response: response)
29
+ remaining: remaining(options: options[:remaining], response: response),
30
+ expires: expires(options: options[:expires], response: response)
28
31
  }
29
32
  end
30
33
 
@@ -33,7 +36,8 @@ class LHC::Throttle < LHC::Interceptor
33
36
  def break_when_quota_reached!
34
37
  options = request.options.dig(:throttle)
35
38
  track = (self.class.track || {}).dig(options[:provider])
36
- return if track.blank? || track[:remaining].blank? || track[:limit].blank?
39
+ return if track.blank? || track[:remaining].blank? || track[:limit].blank? || track[:expires].blank?
40
+ return if Time.zone.now > track[:expires]
37
41
  # avoid floats by multiplying with 100
38
42
  remaining = track[:remaining] * 100
39
43
  limit = track[:limit]
@@ -58,4 +62,20 @@ class LHC::Throttle < LHC::Interceptor
58
62
  end
59
63
  end
60
64
  end
65
+
66
+ def expires(options:, response:)
67
+ @expires ||= begin
68
+ if options.is_a?(Hash) && options[:header] && response.headers.present?
69
+ convert_expires(response.headers[options[:header]]&.to_i)
70
+ else
71
+ convert_expires(options)
72
+ end
73
+ end
74
+ end
75
+
76
+ def convert_expires(value)
77
+ if value.is_a?(Integer)
78
+ Time.zone.at(value).to_datetime
79
+ end
80
+ end
61
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LHC
4
- VERSION ||= '10.4.2'
4
+ VERSION ||= '10.4.3'
5
5
  end
@@ -13,12 +13,14 @@ describe LHC::Throttle do
13
13
  track: true,
14
14
  limit: limit_options,
15
15
  remaining: { header: 'Rate-Limit-Remaining' },
16
+ expires: { header: 'Rate-Limit-Reset' },
16
17
  break: break_option
17
18
  }
18
19
  }
19
20
  end
20
21
  let(:limit_options) { { header: 'Rate-Limit-Limit' } }
21
22
  let(:break_option) { false }
23
+ let(:expires_in) { (Time.zone.now + 1.hour).to_i }
22
24
 
23
25
  before(:each) do
24
26
  LHC::Throttle.track = nil
@@ -28,7 +30,8 @@ describe LHC::Throttle do
28
30
  .to_return(
29
31
  headers: {
30
32
  'Rate-Limit-Limit' => limit,
31
- 'Rate-Limit-Remaining' => remaining
33
+ 'Rate-Limit-Remaining' => remaining,
34
+ 'Rate-Limit-Reset' => expires_in
32
35
  }
33
36
  )
34
37
  end
@@ -87,4 +90,17 @@ describe LHC::Throttle do
87
90
  end
88
91
  end
89
92
  end
93
+
94
+ context 'expires' do
95
+ let(:break_option) { '80%' }
96
+
97
+ it 'attempts another request if the quota expired' do
98
+ LHC.get('http://local.ch', options)
99
+ expect(-> {
100
+ LHC.get('http://local.ch', options)
101
+ }).to raise_error(LHC::Throttle::OutOfQuota, 'Reached predefined quota for local.ch')
102
+ Timecop.travel(Time.zone.now + 2.hours)
103
+ LHC.get('http://local.ch', options)
104
+ end
105
+ end
90
106
  end
@@ -3,5 +3,6 @@
3
3
  require 'pry'
4
4
  require 'webmock/rspec'
5
5
  require 'lhc'
6
+ require 'timecop'
6
7
 
7
8
  Dir[File.join(__dir__, "support/**/*.rb")].each { |f| require f }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lhc
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.4.2
4
+ version: 10.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/local-ch/lhc/contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-22 00:00:00.000000000 Z
11
+ date: 2019-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: 1.26.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: timecop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: webmock
155
169
  requirement: !ruby/object:Gem::Requirement