stripe 5.30.0 → 5.31.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 +4 -4
- data/.github/workflows/ci.yml +34 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +0 -1
- data/README.md +0 -1
- data/VERSION +1 -1
- data/lib/stripe.rb +23 -21
- data/lib/stripe/connection_manager.rb +10 -8
- data/lib/stripe/oauth.rb +4 -3
- data/lib/stripe/resources/account.rb +3 -8
- data/lib/stripe/resources/file.rb +2 -1
- data/lib/stripe/stripe_client.rb +131 -64
- data/lib/stripe/stripe_configuration.rb +25 -9
- data/lib/stripe/stripe_object.rb +23 -0
- data/lib/stripe/util.rb +12 -6
- data/lib/stripe/version.rb +1 -1
- data/test/stripe/connection_manager_test.rb +43 -0
- data/test/stripe/oauth_test.rb +45 -0
- data/test/stripe/stripe_client_test.rb +188 -23
- data/test/stripe/stripe_configuration_test.rb +37 -9
- data/test/stripe/stripe_object_test.rb +10 -0
- data/test/stripe_test.rb +5 -0
- data/test/test_helper.rb +0 -3
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e821f192b447738c35b91b15911de51e0cd138c0e999230747c43e04a1b97c7
|
|
4
|
+
data.tar.gz: ba43636f6bf6e95dfed2daa8078f22d81a4dca5b056dacf12bc979925c6a7786
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9d7e86de7356f7e6a8a929304b330c7692686a31596af70e2ed91c5e15c024102ed9a32f9a81ec07ac585f12a6a853cd28acee37ea95523e1b8788d7041e130
|
|
7
|
+
data.tar.gz: 7ac1ca50526e7dce9f45cd4179dc17f5965ce24f5702dc1605bd449f25f852827b8f24ba6dbb32983142f34037296cd8c0c28927da576915fbbc42e8022f8892
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
on:
|
|
2
|
+
push:
|
|
3
|
+
branches: [ master ]
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ master ]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
lint:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v2
|
|
13
|
+
- name: Set up Ruby
|
|
14
|
+
uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
ruby-version: 2.7
|
|
17
|
+
- name: rubocop
|
|
18
|
+
run: bundle install && bundle exec rake rubocop
|
|
19
|
+
|
|
20
|
+
test:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
strategy:
|
|
23
|
+
matrix:
|
|
24
|
+
ruby-version: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, jruby-9.2.16.0]
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v2
|
|
27
|
+
- name: Set up Ruby
|
|
28
|
+
uses: ruby/setup-ruby@v1
|
|
29
|
+
with:
|
|
30
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
31
|
+
- name: Start stripe-mock
|
|
32
|
+
run: docker run -d -p 12111-12112:12111-12112 stripemock/stripe-mock && sleep 5
|
|
33
|
+
- name: test
|
|
34
|
+
run: bundle install && bundle exec rake test
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.31.0 - 2021-04-02
|
|
4
|
+
* [#968](https://github.com/stripe/stripe-ruby/pull/968) Allow StripeClient to be configured per instance
|
|
5
|
+
* [#971](https://github.com/stripe/stripe-ruby/pull/971) On config change, only clear connection managers for changed config
|
|
6
|
+
* [#972](https://github.com/stripe/stripe-ruby/pull/972) Rename `Stripe.configuration` to `Stripe.config`
|
|
7
|
+
* [#970](https://github.com/stripe/stripe-ruby/pull/970) Reserve some critical field names when adding `StripeObject` accessors
|
|
8
|
+
* [#967](https://github.com/stripe/stripe-ruby/pull/967) CI: github actions
|
|
9
|
+
|
|
3
10
|
## 5.30.0 - 2021-02-22
|
|
4
11
|
* [#965](https://github.com/stripe/stripe-ruby/pull/965) Add support for the Billing Portal Configuration API
|
|
5
12
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/stripe)
|
|
4
4
|
[](https://travis-ci.org/stripe/stripe-ruby)
|
|
5
|
-
[](https://coveralls.io/github/stripe/stripe-ruby?branch=master)
|
|
6
5
|
|
|
7
6
|
The Stripe Ruby library provides convenient access to the Stripe API from
|
|
8
7
|
applications written in the Ruby language. It includes a pre-defined set of
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.
|
|
1
|
+
5.31.0
|
data/lib/stripe.rb
CHANGED
|
@@ -57,34 +57,36 @@ module Stripe
|
|
|
57
57
|
|
|
58
58
|
@app_info = nil
|
|
59
59
|
|
|
60
|
-
@
|
|
60
|
+
@config = Stripe::StripeConfiguration.setup
|
|
61
61
|
|
|
62
62
|
class << self
|
|
63
63
|
extend Forwardable
|
|
64
64
|
|
|
65
|
+
attr_reader :config
|
|
66
|
+
|
|
65
67
|
# User configurable options
|
|
66
|
-
def_delegators :@
|
|
67
|
-
def_delegators :@
|
|
68
|
-
def_delegators :@
|
|
69
|
-
def_delegators :@
|
|
70
|
-
def_delegators :@
|
|
71
|
-
def_delegators :@
|
|
72
|
-
def_delegators :@
|
|
73
|
-
def_delegators :@
|
|
74
|
-
def_delegators :@
|
|
75
|
-
def_delegators :@
|
|
76
|
-
def_delegators :@
|
|
77
|
-
def_delegators :@
|
|
78
|
-
def_delegators :@
|
|
79
|
-
def_delegators :@
|
|
80
|
-
def_delegators :@
|
|
81
|
-
def_delegators :@
|
|
82
|
-
def_delegators :@
|
|
68
|
+
def_delegators :@config, :api_key, :api_key=
|
|
69
|
+
def_delegators :@config, :api_version, :api_version=
|
|
70
|
+
def_delegators :@config, :stripe_account, :stripe_account=
|
|
71
|
+
def_delegators :@config, :api_base, :api_base=
|
|
72
|
+
def_delegators :@config, :uploads_base, :uploads_base=
|
|
73
|
+
def_delegators :@config, :connect_base, :connect_base=
|
|
74
|
+
def_delegators :@config, :open_timeout, :open_timeout=
|
|
75
|
+
def_delegators :@config, :read_timeout, :read_timeout=
|
|
76
|
+
def_delegators :@config, :write_timeout, :write_timeout=
|
|
77
|
+
def_delegators :@config, :proxy, :proxy=
|
|
78
|
+
def_delegators :@config, :verify_ssl_certs, :verify_ssl_certs=
|
|
79
|
+
def_delegators :@config, :ca_bundle_path, :ca_bundle_path=
|
|
80
|
+
def_delegators :@config, :log_level, :log_level=
|
|
81
|
+
def_delegators :@config, :logger, :logger=
|
|
82
|
+
def_delegators :@config, :max_network_retries, :max_network_retries=
|
|
83
|
+
def_delegators :@config, :enable_telemetry=, :enable_telemetry?
|
|
84
|
+
def_delegators :@config, :client_id=, :client_id
|
|
83
85
|
|
|
84
86
|
# Internal configurations
|
|
85
|
-
def_delegators :@
|
|
86
|
-
def_delegators :@
|
|
87
|
-
def_delegators :@
|
|
87
|
+
def_delegators :@config, :max_network_retry_delay
|
|
88
|
+
def_delegators :@config, :initial_network_retry_delay
|
|
89
|
+
def_delegators :@config, :ca_store
|
|
88
90
|
end
|
|
89
91
|
|
|
90
92
|
# Gets the application for a plugin that's identified some. See
|
|
@@ -15,8 +15,10 @@ module Stripe
|
|
|
15
15
|
# by `StripeClient` to determine whether a connection manager should be
|
|
16
16
|
# garbage collected or not.
|
|
17
17
|
attr_reader :last_used
|
|
18
|
+
attr_reader :config
|
|
18
19
|
|
|
19
|
-
def initialize
|
|
20
|
+
def initialize(config = Stripe.config)
|
|
21
|
+
@config = config
|
|
20
22
|
@active_connections = {}
|
|
21
23
|
@last_used = Util.monotonic_time
|
|
22
24
|
|
|
@@ -117,17 +119,17 @@ module Stripe
|
|
|
117
119
|
# reused Go's default for `DefaultTransport`.
|
|
118
120
|
connection.keep_alive_timeout = 30
|
|
119
121
|
|
|
120
|
-
connection.open_timeout =
|
|
121
|
-
connection.read_timeout =
|
|
122
|
+
connection.open_timeout = config.open_timeout
|
|
123
|
+
connection.read_timeout = config.read_timeout
|
|
122
124
|
if connection.respond_to?(:write_timeout=)
|
|
123
|
-
connection.write_timeout =
|
|
125
|
+
connection.write_timeout = config.write_timeout
|
|
124
126
|
end
|
|
125
127
|
|
|
126
128
|
connection.use_ssl = uri.scheme == "https"
|
|
127
129
|
|
|
128
|
-
if
|
|
130
|
+
if config.verify_ssl_certs
|
|
129
131
|
connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
130
|
-
connection.cert_store =
|
|
132
|
+
connection.cert_store = config.ca_store
|
|
131
133
|
else
|
|
132
134
|
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
133
135
|
warn_ssl_verify_none
|
|
@@ -141,10 +143,10 @@ module Stripe
|
|
|
141
143
|
# out those pieces to make passing them into a new connection a little less
|
|
142
144
|
# ugly.
|
|
143
145
|
private def proxy_parts
|
|
144
|
-
if
|
|
146
|
+
if config.proxy.nil?
|
|
145
147
|
[nil, nil, nil, nil]
|
|
146
148
|
else
|
|
147
|
-
u = URI.parse(
|
|
149
|
+
u = URI.parse(config.proxy)
|
|
148
150
|
[u.host, u.port, u.user, u.password]
|
|
149
151
|
end
|
|
150
152
|
end
|
data/lib/stripe/oauth.rb
CHANGED
|
@@ -7,8 +7,8 @@ module Stripe
|
|
|
7
7
|
|
|
8
8
|
def self.execute_resource_request(method, url, params, opts)
|
|
9
9
|
opts = Util.normalize_opts(opts)
|
|
10
|
-
opts[:client] ||= StripeClient.active_client
|
|
11
|
-
opts[:api_base] ||=
|
|
10
|
+
opts[:client] ||= opts[:client] || StripeClient.active_client
|
|
11
|
+
opts[:api_base] ||= opts[:client].config.connect_base
|
|
12
12
|
|
|
13
13
|
super(method, url, params, opts)
|
|
14
14
|
end
|
|
@@ -29,7 +29,8 @@ module Stripe
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def self.authorize_url(params = {}, opts = {})
|
|
32
|
-
|
|
32
|
+
client = opts[:client] || StripeClient.active_client
|
|
33
|
+
base = opts[:connect_base] || client.config.connect_base
|
|
33
34
|
|
|
34
35
|
path = "/oauth/authorize"
|
|
35
36
|
path = "/express" + path if opts[:express]
|
|
@@ -45,12 +45,8 @@ module Stripe
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# @override To make id optional
|
|
48
|
-
def self.retrieve(id =
|
|
49
|
-
id
|
|
50
|
-
nil
|
|
51
|
-
else
|
|
52
|
-
Util.check_string_argument!(id)
|
|
53
|
-
end
|
|
48
|
+
def self.retrieve(id = nil, opts = {})
|
|
49
|
+
Util.check_string_argument!(id) if id
|
|
54
50
|
|
|
55
51
|
# Account used to be a singleton, where this method's signature was
|
|
56
52
|
# `(opts={})`. For the sake of not breaking folks who pass in an OAuth
|
|
@@ -136,11 +132,10 @@ module Stripe
|
|
|
136
132
|
client_id: client_id,
|
|
137
133
|
stripe_user_id: id,
|
|
138
134
|
}
|
|
135
|
+
opts = @opts.merge(Util.normalize_opts(opts))
|
|
139
136
|
OAuth.deauthorize(params, opts)
|
|
140
137
|
end
|
|
141
138
|
|
|
142
|
-
ARGUMENT_NOT_PROVIDED = Object.new
|
|
143
|
-
|
|
144
139
|
private def serialize_additional_owners(legal_entity, additional_owners)
|
|
145
140
|
original_value =
|
|
146
141
|
legal_entity
|
|
@@ -25,8 +25,9 @@ module Stripe
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
config = opts[:client]&.config || Stripe.config
|
|
28
29
|
opts = {
|
|
29
|
-
api_base:
|
|
30
|
+
api_base: config.uploads_base,
|
|
30
31
|
content_type: MultipartEncoder::MULTIPART_FORM_DATA,
|
|
31
32
|
}.merge(Util.normalize_opts(opts))
|
|
32
33
|
super
|
data/lib/stripe/stripe_client.rb
CHANGED
|
@@ -9,18 +9,35 @@ module Stripe
|
|
|
9
9
|
class StripeClient
|
|
10
10
|
# A set of all known thread contexts across all threads and a mutex to
|
|
11
11
|
# synchronize global access to them.
|
|
12
|
-
@thread_contexts_with_connection_managers =
|
|
12
|
+
@thread_contexts_with_connection_managers = Set.new
|
|
13
13
|
@thread_contexts_with_connection_managers_mutex = Mutex.new
|
|
14
14
|
@last_connection_manager_gc = Util.monotonic_time
|
|
15
15
|
|
|
16
|
-
# Initializes a new
|
|
17
|
-
|
|
18
|
-
# Takes a connection manager object for backwards compatibility only, and
|
|
19
|
-
# that use is DEPRECATED.
|
|
20
|
-
def initialize(_connection_manager = nil)
|
|
16
|
+
# Initializes a new StripeClient
|
|
17
|
+
def initialize(config_arg = {})
|
|
21
18
|
@system_profiler = SystemProfiler.new
|
|
22
19
|
@last_request_metrics = nil
|
|
23
|
-
|
|
20
|
+
|
|
21
|
+
@config = case config_arg
|
|
22
|
+
when Hash
|
|
23
|
+
Stripe.config.reverse_duplicate_merge(config_arg)
|
|
24
|
+
when Stripe::ConnectionManager
|
|
25
|
+
# Supports accepting a connection manager object for backwards
|
|
26
|
+
# compatibility only, and that use is DEPRECATED.
|
|
27
|
+
Stripe.config.dup
|
|
28
|
+
when Stripe::StripeConfiguration
|
|
29
|
+
config_arg
|
|
30
|
+
when String
|
|
31
|
+
Stripe.config.reverse_duplicate_merge(
|
|
32
|
+
{ api_key: config_arg }
|
|
33
|
+
)
|
|
34
|
+
else
|
|
35
|
+
raise ArgumentError, "Can't handle argument: #{config_arg}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :config
|
|
40
|
+
attr_reader :options
|
|
24
41
|
|
|
25
42
|
# Gets a currently active `StripeClient`. Set for the current thread when
|
|
26
43
|
# `StripeClient#request` is being run so that API operations being executed
|
|
@@ -37,36 +54,51 @@ module Stripe
|
|
|
37
54
|
# clears them from internal tracking in all connection managers across all
|
|
38
55
|
# threads.
|
|
39
56
|
#
|
|
57
|
+
# If passed a `config` object, only clear connection managers for that
|
|
58
|
+
# particular configuration.
|
|
59
|
+
#
|
|
40
60
|
# For internal use only. Does not provide a stable API and may be broken
|
|
41
61
|
# with future non-major changes.
|
|
42
|
-
def self.clear_all_connection_managers
|
|
62
|
+
def self.clear_all_connection_managers(config: nil)
|
|
43
63
|
# Just a quick path for when configuration is being set for the first
|
|
44
64
|
# time before any connections have been opened. There is technically some
|
|
45
65
|
# potential for thread raciness here, but not in a practical sense.
|
|
46
66
|
return if @thread_contexts_with_connection_managers.empty?
|
|
47
67
|
|
|
48
68
|
@thread_contexts_with_connection_managers_mutex.synchronize do
|
|
69
|
+
pruned_contexts = Set.new
|
|
70
|
+
|
|
49
71
|
@thread_contexts_with_connection_managers.each do |thread_context|
|
|
50
72
|
# Note that the thread context itself is not destroyed, but we clear
|
|
51
73
|
# its connection manager and remove our reference to it. If it ever
|
|
52
74
|
# makes a new request we'll give it a new connection manager and
|
|
53
75
|
# it'll go back into `@thread_contexts_with_connection_managers`.
|
|
54
|
-
thread_context.
|
|
55
|
-
|
|
76
|
+
thread_context.default_connection_managers.reject! do |cm_config, cm|
|
|
77
|
+
if config.nil? || config.key == cm_config
|
|
78
|
+
cm.clear
|
|
79
|
+
true
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if thread_context.default_connection_managers.empty?
|
|
84
|
+
pruned_contexts << thread_context
|
|
85
|
+
end
|
|
56
86
|
end
|
|
57
|
-
|
|
87
|
+
|
|
88
|
+
@thread_contexts_with_connection_managers.subtract(pruned_contexts)
|
|
58
89
|
end
|
|
59
90
|
end
|
|
60
91
|
|
|
61
92
|
# A default client for the current thread.
|
|
62
93
|
def self.default_client
|
|
63
|
-
current_thread_context.default_client ||= StripeClient.new
|
|
94
|
+
current_thread_context.default_client ||= StripeClient.new(Stripe.config)
|
|
64
95
|
end
|
|
65
96
|
|
|
66
|
-
# A default connection manager for the current thread
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
97
|
+
# A default connection manager for the current thread scoped to the
|
|
98
|
+
# configuration object that may be provided.
|
|
99
|
+
def self.default_connection_manager(config = Stripe.config)
|
|
100
|
+
current_thread_context.default_connection_managers[config.key] ||= begin
|
|
101
|
+
connection_manager = ConnectionManager.new(config)
|
|
70
102
|
|
|
71
103
|
@thread_contexts_with_connection_managers_mutex.synchronize do
|
|
72
104
|
maybe_gc_connection_managers
|
|
@@ -80,8 +112,9 @@ module Stripe
|
|
|
80
112
|
# Checks if an error is a problem that we should retry on. This includes
|
|
81
113
|
# both socket errors that may represent an intermittent problem and some
|
|
82
114
|
# special HTTP statuses.
|
|
83
|
-
def self.should_retry?(error,
|
|
84
|
-
|
|
115
|
+
def self.should_retry?(error,
|
|
116
|
+
method:, num_retries:, config: Stripe.config)
|
|
117
|
+
return false if num_retries >= config.max_network_retries
|
|
85
118
|
|
|
86
119
|
case error
|
|
87
120
|
when Net::OpenTimeout, Net::ReadTimeout
|
|
@@ -127,13 +160,13 @@ module Stripe
|
|
|
127
160
|
end
|
|
128
161
|
end
|
|
129
162
|
|
|
130
|
-
def self.sleep_time(num_retries)
|
|
163
|
+
def self.sleep_time(num_retries, config: Stripe.config)
|
|
131
164
|
# Apply exponential backoff with initial_network_retry_delay on the
|
|
132
165
|
# number of num_retries so far as inputs. Do not allow the number to
|
|
133
166
|
# exceed max_network_retry_delay.
|
|
134
167
|
sleep_seconds = [
|
|
135
|
-
|
|
136
|
-
|
|
168
|
+
config.initial_network_retry_delay * (2**(num_retries - 1)),
|
|
169
|
+
config.max_network_retry_delay,
|
|
137
170
|
].min
|
|
138
171
|
|
|
139
172
|
# Apply some jitter by randomizing the value in the range of
|
|
@@ -141,9 +174,7 @@ module Stripe
|
|
|
141
174
|
sleep_seconds *= (0.5 * (1 + rand))
|
|
142
175
|
|
|
143
176
|
# But never sleep less than the base sleep seconds.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
sleep_seconds
|
|
177
|
+
[config.initial_network_retry_delay, sleep_seconds].max
|
|
147
178
|
end
|
|
148
179
|
|
|
149
180
|
# Gets the connection manager in use for the current `StripeClient`.
|
|
@@ -187,8 +218,8 @@ module Stripe
|
|
|
187
218
|
raise ArgumentError, "path should be a string" \
|
|
188
219
|
unless path.is_a?(String)
|
|
189
220
|
|
|
190
|
-
api_base ||=
|
|
191
|
-
api_key ||=
|
|
221
|
+
api_base ||= config.api_base
|
|
222
|
+
api_key ||= config.api_key
|
|
192
223
|
params = Util.objects_to_ids(params)
|
|
193
224
|
|
|
194
225
|
check_api_key!(api_key)
|
|
@@ -231,10 +262,12 @@ module Stripe
|
|
|
231
262
|
context.query = query
|
|
232
263
|
|
|
233
264
|
http_resp = execute_request_with_rescues(method, api_base, context) do
|
|
234
|
-
self.class
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
265
|
+
self.class
|
|
266
|
+
.default_connection_manager(config)
|
|
267
|
+
.execute_request(method, url,
|
|
268
|
+
body: body,
|
|
269
|
+
headers: headers,
|
|
270
|
+
query: query)
|
|
238
271
|
end
|
|
239
272
|
|
|
240
273
|
begin
|
|
@@ -246,13 +279,21 @@ module Stripe
|
|
|
246
279
|
# If being called from `StripeClient#request`, put the last response in
|
|
247
280
|
# thread-local memory so that it can be returned to the user. Don't store
|
|
248
281
|
# anything otherwise so that we don't leak memory.
|
|
249
|
-
|
|
250
|
-
self.class.current_thread_context.last_responses[object_id] = resp
|
|
251
|
-
end
|
|
282
|
+
store_last_response(object_id, resp)
|
|
252
283
|
|
|
253
284
|
[resp, api_key]
|
|
254
285
|
end
|
|
255
286
|
|
|
287
|
+
def store_last_response(object_id, resp)
|
|
288
|
+
return unless last_response_has_key?(object_id)
|
|
289
|
+
|
|
290
|
+
self.class.current_thread_context.last_responses[object_id] = resp
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def last_response_has_key?(object_id)
|
|
294
|
+
self.class.current_thread_context.last_responses&.key?(object_id)
|
|
295
|
+
end
|
|
296
|
+
|
|
256
297
|
#
|
|
257
298
|
# private
|
|
258
299
|
#
|
|
@@ -328,11 +369,6 @@ module Stripe
|
|
|
328
369
|
# the user hasn't specified their own.
|
|
329
370
|
attr_accessor :default_client
|
|
330
371
|
|
|
331
|
-
# A default `ConnectionManager` for the thread. Normally shared between
|
|
332
|
-
# all `StripeClient` objects on a particular thread, and created so as to
|
|
333
|
-
# minimize the number of open connections that an application needs.
|
|
334
|
-
attr_accessor :default_connection_manager
|
|
335
|
-
|
|
336
372
|
# A temporary map of object IDs to responses from last executed API
|
|
337
373
|
# calls. Used to return a responses from calls to `StripeClient#request`.
|
|
338
374
|
#
|
|
@@ -345,6 +381,17 @@ module Stripe
|
|
|
345
381
|
# because that's wrapped in an `ensure` block, they should never leave
|
|
346
382
|
# garbage in `Thread.current`.
|
|
347
383
|
attr_accessor :last_responses
|
|
384
|
+
|
|
385
|
+
# A map of connection mangers for the thread. Normally shared between
|
|
386
|
+
# all `StripeClient` objects on a particular thread, and created so as to
|
|
387
|
+
# minimize the number of open connections that an application needs.
|
|
388
|
+
def default_connection_managers
|
|
389
|
+
@default_connection_managers ||= {}
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def reset_connection_managers
|
|
393
|
+
@default_connection_managers = {}
|
|
394
|
+
end
|
|
348
395
|
end
|
|
349
396
|
|
|
350
397
|
# Access data stored for `StripeClient` within the thread's current
|
|
@@ -380,24 +427,32 @@ module Stripe
|
|
|
380
427
|
last_used_threshold =
|
|
381
428
|
Util.monotonic_time - CONNECTION_MANAGER_GC_LAST_USED_EXPIRY
|
|
382
429
|
|
|
383
|
-
|
|
430
|
+
pruned_contexts = []
|
|
431
|
+
@thread_contexts_with_connection_managers.each do |thread_context|
|
|
432
|
+
thread_context
|
|
433
|
+
.default_connection_managers
|
|
434
|
+
.each do |config_key, connection_manager|
|
|
435
|
+
next if connection_manager.last_used > last_used_threshold
|
|
436
|
+
|
|
437
|
+
connection_manager.clear
|
|
438
|
+
thread_context.default_connection_managers.delete(config_key)
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
384
442
|
@thread_contexts_with_connection_managers.each do |thread_context|
|
|
385
|
-
|
|
386
|
-
next if connection_manager.last_used > last_used_threshold
|
|
443
|
+
next unless thread_context.default_connection_managers.empty?
|
|
387
444
|
|
|
388
|
-
|
|
389
|
-
thread_context.default_connection_manager = nil
|
|
390
|
-
pruned_thread_contexts << thread_context
|
|
445
|
+
pruned_contexts << thread_context
|
|
391
446
|
end
|
|
392
447
|
|
|
393
|
-
@thread_contexts_with_connection_managers -=
|
|
448
|
+
@thread_contexts_with_connection_managers -= pruned_contexts
|
|
394
449
|
@last_connection_manager_gc = Util.monotonic_time
|
|
395
450
|
|
|
396
|
-
|
|
451
|
+
pruned_contexts.count
|
|
397
452
|
end
|
|
398
453
|
|
|
399
454
|
private def api_url(url = "", api_base = nil)
|
|
400
|
-
(api_base ||
|
|
455
|
+
(api_base || config.api_base) + url
|
|
401
456
|
end
|
|
402
457
|
|
|
403
458
|
private def check_api_key!(api_key)
|
|
@@ -471,7 +526,7 @@ module Stripe
|
|
|
471
526
|
notify_request_end(context, request_duration, http_status,
|
|
472
527
|
num_retries, user_data)
|
|
473
528
|
|
|
474
|
-
if
|
|
529
|
+
if config.enable_telemetry? && context.request_id
|
|
475
530
|
request_duration_ms = (request_duration * 1000).to_i
|
|
476
531
|
@last_request_metrics =
|
|
477
532
|
StripeRequestMetrics.new(context.request_id, request_duration_ms)
|
|
@@ -498,9 +553,12 @@ module Stripe
|
|
|
498
553
|
notify_request_end(context, request_duration, http_status, num_retries,
|
|
499
554
|
user_data)
|
|
500
555
|
|
|
501
|
-
if self.class.should_retry?(e,
|
|
556
|
+
if self.class.should_retry?(e,
|
|
557
|
+
method: method,
|
|
558
|
+
num_retries: num_retries,
|
|
559
|
+
config: config)
|
|
502
560
|
num_retries += 1
|
|
503
|
-
sleep self.class.sleep_time(num_retries)
|
|
561
|
+
sleep self.class.sleep_time(num_retries, config: config)
|
|
504
562
|
retry
|
|
505
563
|
end
|
|
506
564
|
|
|
@@ -622,7 +680,8 @@ module Stripe
|
|
|
622
680
|
error_param: error_data[:param],
|
|
623
681
|
error_type: error_data[:type],
|
|
624
682
|
idempotency_key: context.idempotency_key,
|
|
625
|
-
request_id: context.request_id
|
|
683
|
+
request_id: context.request_id,
|
|
684
|
+
config: config)
|
|
626
685
|
|
|
627
686
|
# The standard set of arguments that can be used to initialize most of
|
|
628
687
|
# the exceptions.
|
|
@@ -671,7 +730,8 @@ module Stripe
|
|
|
671
730
|
error_code: error_code,
|
|
672
731
|
error_description: description,
|
|
673
732
|
idempotency_key: context.idempotency_key,
|
|
674
|
-
request_id: context.request_id
|
|
733
|
+
request_id: context.request_id,
|
|
734
|
+
config: config)
|
|
675
735
|
|
|
676
736
|
args = {
|
|
677
737
|
http_status: resp.http_status, http_body: resp.http_body,
|
|
@@ -703,7 +763,8 @@ module Stripe
|
|
|
703
763
|
Util.log_error("Stripe network error",
|
|
704
764
|
error_message: error.message,
|
|
705
765
|
idempotency_key: context.idempotency_key,
|
|
706
|
-
request_id: context.request_id
|
|
766
|
+
request_id: context.request_id,
|
|
767
|
+
config: config)
|
|
707
768
|
|
|
708
769
|
errors, message = NETWORK_ERROR_MESSAGES_MAP.detect do |(e, _)|
|
|
709
770
|
error.is_a?(e)
|
|
@@ -714,7 +775,7 @@ module Stripe
|
|
|
714
775
|
"with Stripe. Please let us know at support@stripe.com."
|
|
715
776
|
end
|
|
716
777
|
|
|
717
|
-
api_base ||=
|
|
778
|
+
api_base ||= config.api_base
|
|
718
779
|
message = message % api_base
|
|
719
780
|
|
|
720
781
|
message += " Request was retried #{num_retries} times." if num_retries > 0
|
|
@@ -735,7 +796,7 @@ module Stripe
|
|
|
735
796
|
"Content-Type" => "application/x-www-form-urlencoded",
|
|
736
797
|
}
|
|
737
798
|
|
|
738
|
-
if
|
|
799
|
+
if config.enable_telemetry? && !@last_request_metrics.nil?
|
|
739
800
|
headers["X-Stripe-Client-Telemetry"] = JSON.generate(
|
|
740
801
|
last_request_metrics: @last_request_metrics.payload
|
|
741
802
|
)
|
|
@@ -743,12 +804,12 @@ module Stripe
|
|
|
743
804
|
|
|
744
805
|
# It is only safe to retry network failures on post and delete
|
|
745
806
|
# requests if we add an Idempotency-Key header
|
|
746
|
-
if %i[post delete].include?(method) &&
|
|
807
|
+
if %i[post delete].include?(method) && config.max_network_retries > 0
|
|
747
808
|
headers["Idempotency-Key"] ||= SecureRandom.uuid
|
|
748
809
|
end
|
|
749
810
|
|
|
750
|
-
headers["Stripe-Version"] =
|
|
751
|
-
headers["Stripe-Account"] =
|
|
811
|
+
headers["Stripe-Version"] = config.api_version if config.api_version
|
|
812
|
+
headers["Stripe-Account"] = config.stripe_account if config.stripe_account
|
|
752
813
|
|
|
753
814
|
user_agent = @system_profiler.user_agent
|
|
754
815
|
begin
|
|
@@ -772,11 +833,13 @@ module Stripe
|
|
|
772
833
|
idempotency_key: context.idempotency_key,
|
|
773
834
|
method: context.method,
|
|
774
835
|
num_retries: num_retries,
|
|
775
|
-
path: context.path
|
|
836
|
+
path: context.path,
|
|
837
|
+
config: config)
|
|
776
838
|
Util.log_debug("Request details",
|
|
777
839
|
body: context.body,
|
|
778
840
|
idempotency_key: context.idempotency_key,
|
|
779
|
-
query: context.query
|
|
841
|
+
query: context.query,
|
|
842
|
+
config: config)
|
|
780
843
|
end
|
|
781
844
|
|
|
782
845
|
private def log_response(context, request_start, status, body)
|
|
@@ -788,11 +851,13 @@ module Stripe
|
|
|
788
851
|
method: context.method,
|
|
789
852
|
path: context.path,
|
|
790
853
|
request_id: context.request_id,
|
|
791
|
-
status: status
|
|
854
|
+
status: status,
|
|
855
|
+
config: config)
|
|
792
856
|
Util.log_debug("Response details",
|
|
793
857
|
body: body,
|
|
794
858
|
idempotency_key: context.idempotency_key,
|
|
795
|
-
request_id: context.request_id
|
|
859
|
+
request_id: context.request_id,
|
|
860
|
+
config: config)
|
|
796
861
|
|
|
797
862
|
return unless context.request_id
|
|
798
863
|
|
|
@@ -800,7 +865,8 @@ module Stripe
|
|
|
800
865
|
idempotency_key: context.idempotency_key,
|
|
801
866
|
request_id: context.request_id,
|
|
802
867
|
url: Util.request_id_dashboard_url(context.request_id,
|
|
803
|
-
context.api_key)
|
|
868
|
+
context.api_key),
|
|
869
|
+
config: config)
|
|
804
870
|
end
|
|
805
871
|
|
|
806
872
|
private def log_response_error(context, request_start, error)
|
|
@@ -810,7 +876,8 @@ module Stripe
|
|
|
810
876
|
error_message: error.message,
|
|
811
877
|
idempotency_key: context.idempotency_key,
|
|
812
878
|
method: context.method,
|
|
813
|
-
path: context.path
|
|
879
|
+
path: context.path,
|
|
880
|
+
config: config)
|
|
814
881
|
end
|
|
815
882
|
|
|
816
883
|
# RequestLogContext stores information about a request that's begin made so
|