springcm-sdk 0.3.6 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2bcbec6f89c659710286d4dac5b6e6197272ca2b90a20202807d68a953bfd4ee
4
- data.tar.gz: c8e2f2e943de9719f61d47dec3a5f3c247cbb99ce4b33e852da986a4acd595e2
3
+ metadata.gz: 4ede0e8cbe39a1ba56490a8747d394136877c4ba297f42bc618d665a37822b5b
4
+ data.tar.gz: 2c6c5bf9194b9f63f937f491cd3522d8175db3d8aabd5cf799b8a09aba7689e6
5
5
  SHA512:
6
- metadata.gz: be09de4cbef4485fd4ae2749f158f12cb23f5bfbdb7377a81fe989f793fab61c4dadd6948241646adf8a6bcd8870c2da300a361208115477e791396ffb4ba10e
7
- data.tar.gz: 336f3fd0bf01bd1b6a89db940a76260aca9a25b5fdc2561de1516336832b7124c9ff8e946770eda7331d727746d84af1a243c72de9920dad0350021feb796a1e
6
+ metadata.gz: 9aee61e667d073e51bc57f7e8aa00c67e6f47067cc106b11e1caee6306836e390035df29d63714f7f10c8d6351bbca8eaabca34ef95a65a4cc71eecbd60f9874
7
+ data.tar.gz: 40aeda6cd074142c6546a3451fd29c495dc1f1a73bebce8dab2d2382f730e268cc5690de41d9c89b7b5203d149a5915a7997802e871b7bc559c3e70558271512
data/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to springcm-sdk will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.4.0] - 2019-12-27
8
+ ### Added
9
+ * Faraday middleware for authorization expiration and rate limit handling.
10
+ * Faraday middleware for retrying on Faraday::ConnectionFailed. Can be
11
+ disabled via new Client options.
12
+
13
+ ### Changed
14
+ * Adjust auth window to re-authenticate no more than 5 minutes before
15
+ access token expiration.
16
+
7
17
  ## [0.3.6] - 2019-12-23
8
18
  ### Changed
9
19
  * Fix resource list behavior for history items. Was returning the document's
@@ -79,7 +89,7 @@ All notable changes to springcm-sdk will be documented in this file.
79
89
  ### Added
80
90
  * Initial release to reserve gem name
81
91
 
82
- [Unreleased]: https://github.com/paulholden2/springcm-sdk/compare/0.3.6...HEAD
92
+ [Unreleased]: https://github.com/paulholden2/springcm-sdk/compare/0.4.0...HEAD
83
93
  [0.1.0]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.1.0
84
94
  [0.1.1]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.1.1
85
95
  [0.1.2]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.1.2
@@ -91,3 +101,4 @@ All notable changes to springcm-sdk will be documented in this file.
91
101
  [0.3.4]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.4
92
102
  [0.3.5]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.5
93
103
  [0.3.6]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.6
104
+ [0.4.0]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.4.0
data/bin/console CHANGED
File without changes
data/exe/springcm CHANGED
File without changes
@@ -3,19 +3,31 @@ require "json"
3
3
  require "springcm-sdk/account"
4
4
  require "springcm-sdk/folder"
5
5
  require "springcm-sdk/document"
6
+ require "springcm-sdk/middleware"
6
7
 
7
8
  module Springcm
8
9
  class Client
10
+ # Default API client options
11
+ DEFAULT_OPTIONS = {
12
+ # If true, the client will use a simple retry mechanism when connection
13
+ # to the API server fails due to e.g. temporary Internet service outage.
14
+ # The connection is re-attempted up to five times, delaying 2 ** n
15
+ # seconds between attempts, where n is the number of previous attempts.
16
+ retry_connection_failed: true
17
+ }.freeze
18
+
9
19
  attr_reader :access_token
10
20
 
11
21
  # @param data_center [String] Data center name, e.g. uatna11
12
22
  # @param client_id [String] Your API client ID
13
23
  # @param client_secret [String] Your API client secret
14
- def initialize(data_center, client_id, client_secret)
24
+ # @parma options [Hash] API client options
25
+ def initialize(data_center, client_id, client_secret, options=DEFAULT_OPTIONS)
15
26
  if !["na11", "uatna11", "eu11", "eu21", "na21", "us11"].include?(data_center)
16
27
  raise Springcm::ConnectionInfoError.new("Invalid data center '#{data_center.to_s}'")
17
28
  end
18
29
 
30
+ @options = options
19
31
  @data_center = data_center
20
32
  @client_id = client_id
21
33
  @client_secret = client_secret
@@ -28,7 +40,12 @@ module Springcm
28
40
  # @param safe If truthy, connection failure does not raise an exception
29
41
  # @return [Boolean] Whether connection was successful
30
42
  def connect(safe=true)
31
- conn = Faraday.new(url: auth_url)
43
+ conn = Faraday.new(url: auth_url) do |conn|
44
+ conn.request :retry, retry_statuses: [429], exceptions: [Springcm::RateLimitExceededError]
45
+ conn.use Springcm::Middleware::RateLimit
46
+ conn.use Springcm::Middleware::RetryConnectionFailed if @options[:retry_connection_failed]
47
+ conn.adapter :net_http
48
+ end
32
49
  res = conn.post do |req|
33
50
  req.headers['Content-Type'] = 'application/json'
34
51
  req.body = {
@@ -39,7 +56,7 @@ module Springcm
39
56
  if res.success?
40
57
  data = JSON.parse(res.body)
41
58
  @access_token = data.fetch("access_token")
42
- @expiry = Time.now + data.fetch("expires_in")
59
+ @expiry = Time.now + data.fetch("expires_in") - 300
43
60
  else
44
61
  @access_token = nil
45
62
  @expiry = nil
@@ -169,15 +186,29 @@ module Springcm
169
186
  end
170
187
 
171
188
  def authorized_connection(*options)
189
+ if !authenticated?
190
+ connect!
191
+ end
192
+
172
193
  Faraday.new(*options) do |conn|
173
194
  options = [{
174
195
  max: 10,
175
196
  interval: 1,
176
197
  interval_randomness: 0.5,
177
198
  backoff_factor: 2,
178
- retry_statuses: [429]
199
+ retry_statuses: [401, 429],
200
+ exceptions: [Springcm::AuthExpiredError, Springcm::RateLimitExceededError],
201
+ retry_block: -> (env, options, retries, exception) {
202
+ if exception.class == Springcm::AuthExpiredError
203
+ connect!
204
+ env.request_headers['Authorization'] = "bearer #{@access_token}"
205
+ end
206
+ }
179
207
  }]
180
208
  conn.request :retry, *options
209
+ conn.use Springcm::Middleware::RateLimit
210
+ conn.use Springcm::Middleware::AuthExpire
211
+ conn.use Springcm::Middleware::RetryConnectionFailed if @options[:retry_connection_failed]
181
212
  conn.adapter :net_http
182
213
  conn.authorization('bearer', @access_token)
183
214
  end
@@ -0,0 +1,20 @@
1
+ module Springcm
2
+ module Middleware
3
+ class AuthExpire
4
+ attr_reader :options
5
+
6
+ def initialize(app, options={})
7
+ @app = app
8
+ @options = options
9
+ end
10
+
11
+ def call(env)
12
+ @app.call(env).on_complete do |response_env|
13
+ if response_env[:status] == 401
14
+ raise Springcm::AuthExpiredError.new
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module Springcm
2
+ module Middleware
3
+ class RateLimit
4
+ attr_reader :options
5
+
6
+ def initialize(app, options={})
7
+ @app = app
8
+ @options = options
9
+ end
10
+
11
+ def call(env)
12
+ @app.call(env).on_complete do |response_env|
13
+ body = JSON.parse(response_env[:body])
14
+ if body.fetch("Error", {}).fetch("ErrorCode", nil) == 103
15
+ raise Springcm::RateLimitExceededError.new
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module Springcm
2
+ module Middleware
3
+ class RetryConnectionFailed
4
+ attr_reader :options
5
+
6
+ def initialize(app, options={ retries: 5 })
7
+ @app = app
8
+ @options = options
9
+ end
10
+
11
+ def call(env)
12
+ retries = @options[:retries]
13
+ delay = 1
14
+ begin
15
+ @app.call(env).on_complete do |response_env|
16
+ end
17
+ rescue Faraday::ConnectionFailed => err
18
+ if retries > 0
19
+ retries -= 1
20
+ sleep delay
21
+ delay *= 2
22
+ retry
23
+ else
24
+ raise err
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ require "springcm-sdk/middleware/rate_limit"
2
+ require "springcm-sdk/middleware/auth_expired"
3
+ require "springcm-sdk/middleware/retry_connection_failed"
@@ -1,3 +1,3 @@
1
1
  module Springcm
2
- VERSION = "0.3.6"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/springcm-sdk.rb CHANGED
@@ -20,4 +20,16 @@ module Springcm
20
20
  super("Invalid Client Id or Client Secret")
21
21
  end
22
22
  end
23
+
24
+ class AuthExpiredError < Error
25
+ def initialize
26
+ super("Authorization expired")
27
+ end
28
+ end
29
+
30
+ class RateLimitExceededError < Error
31
+ def initialize
32
+ super("Rate limit exceeded")
33
+ end
34
+ end
23
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: springcm-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Holden
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-24 00:00:00.000000000 Z
11
+ date: 2019-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -167,6 +167,10 @@ files:
167
167
  - lib/springcm-sdk/folder.rb
168
168
  - lib/springcm-sdk/helpers.rb
169
169
  - lib/springcm-sdk/history_item.rb
170
+ - lib/springcm-sdk/middleware.rb
171
+ - lib/springcm-sdk/middleware/auth_expired.rb
172
+ - lib/springcm-sdk/middleware/rate_limit.rb
173
+ - lib/springcm-sdk/middleware/retry_connection_failed.rb
170
174
  - lib/springcm-sdk/mixins/access_level.rb
171
175
  - lib/springcm-sdk/mixins/attributes.rb
172
176
  - lib/springcm-sdk/mixins/documents.rb
@@ -183,7 +187,7 @@ metadata:
183
187
  allowed_push_host: https://rubygems.org
184
188
  homepage_uri: https://github.com/paulholden2/springcm-sdk
185
189
  source_code_uri: https://github.com/paulholden2/springcm-sdk
186
- documentation_uri: https://rubydoc.info/github/paulholden2/springcm-sdk/0.3.6
190
+ documentation_uri: https://rubydoc.info/github/paulholden2/springcm-sdk/0.4.0
187
191
  changelog_uri: https://github.com/paulholden2/springcm-sdk/blob/master/CHANGELOG.md
188
192
  post_install_message:
189
193
  rdoc_options: []