hearth 1.0.0.pre1 → 1.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -4
- data/VERSION +1 -1
- data/lib/hearth/anonymous_auth_resolver.rb +11 -0
- data/lib/hearth/api_error.rb +15 -1
- data/lib/hearth/auth_option.rb +21 -0
- data/lib/hearth/auth_schemes/anonymous.rb +21 -0
- data/lib/hearth/auth_schemes/http_api_key.rb +16 -0
- data/lib/hearth/auth_schemes/http_basic.rb +16 -0
- data/lib/hearth/auth_schemes/http_bearer.rb +16 -0
- data/lib/hearth/auth_schemes/http_digest.rb +16 -0
- data/lib/hearth/auth_schemes.rb +32 -0
- data/lib/hearth/checksums.rb +31 -0
- data/lib/hearth/client.rb +66 -0
- data/lib/hearth/client_stubs.rb +128 -0
- data/lib/hearth/config/env_provider.rb +53 -0
- data/lib/hearth/config/resolver.rb +53 -0
- data/lib/hearth/configuration.rb +15 -0
- data/lib/hearth/connection_pool.rb +77 -0
- data/lib/hearth/context.rb +29 -4
- data/lib/hearth/dns/host_address.rb +27 -0
- data/lib/hearth/dns/host_resolver.rb +92 -0
- data/lib/hearth/dns.rb +48 -0
- data/lib/hearth/endpoint_rules.rb +154 -0
- data/lib/hearth/http/api_error.rb +4 -8
- data/lib/hearth/http/client.rb +206 -59
- data/lib/hearth/http/error_inspector.rb +85 -0
- data/lib/hearth/http/error_parser.rb +18 -20
- data/lib/hearth/http/field.rb +49 -0
- data/lib/hearth/http/fields.rb +117 -0
- data/lib/hearth/http/header_list_builder.rb +42 -0
- data/lib/hearth/http/header_list_parser.rb +92 -0
- data/lib/hearth/http/middleware/content_length.rb +7 -4
- data/lib/hearth/http/middleware/content_md5.rb +30 -0
- data/lib/hearth/http/middleware/request_compression.rb +154 -0
- data/lib/hearth/http/middleware.rb +12 -0
- data/lib/hearth/http/networking_error.rb +1 -14
- data/lib/hearth/http/request.rb +83 -56
- data/lib/hearth/http/response.rb +42 -13
- data/lib/hearth/http.rb +16 -5
- data/lib/hearth/identities/anonymous.rb +8 -0
- data/lib/hearth/identities/http_api_key.rb +16 -0
- data/lib/hearth/identities/http_bearer.rb +16 -0
- data/lib/hearth/identities/http_login.rb +20 -0
- data/lib/hearth/identities.rb +21 -0
- data/lib/hearth/identity_provider.rb +17 -0
- data/lib/hearth/interceptor.rb +506 -0
- data/lib/hearth/interceptor_context.rb +40 -0
- data/lib/hearth/interceptor_list.rb +48 -0
- data/lib/hearth/interceptors.rb +76 -0
- data/lib/hearth/json.rb +4 -4
- data/lib/hearth/middleware/auth.rb +103 -0
- data/lib/hearth/middleware/build.rb +32 -1
- data/lib/hearth/middleware/endpoint.rb +79 -0
- data/lib/hearth/middleware/host_prefix.rb +11 -8
- data/lib/hearth/middleware/initialize.rb +57 -0
- data/lib/hearth/middleware/parse.rb +45 -7
- data/lib/hearth/middleware/retry.rb +105 -24
- data/lib/hearth/middleware/send.rb +137 -26
- data/lib/hearth/middleware/sign.rb +65 -0
- data/lib/hearth/middleware/validate.rb +11 -1
- data/lib/hearth/middleware.rb +20 -8
- data/lib/hearth/middleware_stack.rb +2 -44
- data/lib/hearth/networking_error.rb +18 -0
- data/lib/hearth/number_helper.rb +3 -3
- data/lib/hearth/output.rb +8 -4
- data/lib/hearth/plugin_list.rb +53 -0
- data/lib/hearth/query/param.rb +56 -0
- data/lib/hearth/query/param_list.rb +54 -0
- data/lib/hearth/query/param_matcher.rb +31 -0
- data/lib/hearth/refreshing_identity_provider.rb +63 -0
- data/lib/hearth/request.rb +22 -0
- data/lib/hearth/response.rb +36 -0
- data/lib/hearth/retry/adaptive.rb +60 -0
- data/lib/hearth/retry/capacity_not_available_error.rb +9 -0
- data/lib/hearth/retry/client_rate_limiter.rb +145 -0
- data/lib/hearth/retry/exponential_backoff.rb +15 -0
- data/lib/hearth/retry/retry_quota.rb +56 -0
- data/lib/hearth/retry/standard.rb +46 -0
- data/lib/hearth/retry.rb +29 -0
- data/lib/hearth/signers/anonymous.rb +16 -0
- data/lib/hearth/signers/http_api_key.rb +29 -0
- data/lib/hearth/signers/http_basic.rb +23 -0
- data/lib/hearth/signers/http_bearer.rb +19 -0
- data/lib/hearth/signers/http_digest.rb +19 -0
- data/lib/hearth/signers.rb +23 -0
- data/lib/hearth/structure.rb +7 -3
- data/lib/hearth/stubs.rb +38 -0
- data/lib/hearth/time_helper.rb +6 -5
- data/lib/hearth/validator.rb +60 -5
- data/lib/hearth/waiters/poller.rb +10 -9
- data/lib/hearth/waiters/waiter.rb +23 -9
- data/lib/hearth/xml/formatter.rb +11 -2
- data/lib/hearth/xml/node.rb +2 -3
- data/lib/hearth/xml/node_matcher.rb +0 -1
- data/lib/hearth.rb +37 -6
- data/sig/lib/hearth/aliases.rbs +6 -0
- data/sig/lib/hearth/anonymous_auth_resolver.rbs +5 -0
- data/sig/lib/hearth/api_error.rbs +13 -0
- data/sig/lib/hearth/auth_option.rbs +11 -0
- data/sig/lib/hearth/auth_schemes/anonymous.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_api_key.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_basic.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_bearer.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_digest.rbs +7 -0
- data/sig/lib/hearth/auth_schemes.rbs +13 -0
- data/sig/lib/hearth/block_io.rbs +9 -0
- data/sig/lib/hearth/client.rbs +9 -0
- data/sig/lib/hearth/client_stubs.rbs +5 -0
- data/sig/lib/hearth/configuration.rbs +7 -0
- data/sig/lib/hearth/dns/host_address.rbs +11 -0
- data/sig/lib/hearth/dns/host_resolver.rbs +19 -0
- data/sig/lib/hearth/endpoint_rules.rbs +17 -0
- data/sig/lib/hearth/http/api_error.rbs +13 -0
- data/sig/lib/hearth/http/client.rbs +9 -0
- data/sig/lib/hearth/http/field.rbs +19 -0
- data/sig/lib/hearth/http/fields.rbs +43 -0
- data/sig/lib/hearth/http/header_list_builder.rbs +15 -0
- data/sig/lib/hearth/http/header_list_parser.rbs +19 -0
- data/sig/lib/hearth/http/networking_error.rbs +6 -0
- data/sig/lib/hearth/http/request.rbs +25 -0
- data/sig/lib/hearth/http/response.rbs +21 -0
- data/sig/lib/hearth/identities/anonymous.rbs +6 -0
- data/sig/lib/hearth/identities/http_api_key.rbs +9 -0
- data/sig/lib/hearth/identities/http_bearer.rbs +9 -0
- data/sig/lib/hearth/identities/http_login.rbs +11 -0
- data/sig/lib/hearth/identities.rbs +9 -0
- data/sig/lib/hearth/identity_provider.rbs +7 -0
- data/sig/lib/hearth/interceptor.rbs +9 -0
- data/sig/lib/hearth/interceptor_context.rbs +17 -0
- data/sig/lib/hearth/interceptor_list.rbs +16 -0
- data/sig/lib/hearth/interfaces.rbs +87 -0
- data/sig/lib/hearth/json/parse_error.rbs +9 -0
- data/sig/lib/hearth/networking_error.rbs +7 -0
- data/sig/lib/hearth/output.rbs +11 -0
- data/sig/lib/hearth/plugin_list.rbs +13 -0
- data/sig/lib/hearth/query/param.rbs +17 -0
- data/sig/lib/hearth/query/param_list.rbs +25 -0
- data/sig/lib/hearth/refreshing_identity_provider.rbs +10 -0
- data/sig/lib/hearth/request.rbs +9 -0
- data/sig/lib/hearth/response.rbs +11 -0
- data/sig/lib/hearth/retry/adaptive.rbs +13 -0
- data/sig/lib/hearth/retry/exponential_backoff.rbs +7 -0
- data/sig/lib/hearth/retry/standard.rbs +13 -0
- data/sig/lib/hearth/retry/strategy.rbs +11 -0
- data/sig/lib/hearth/retry.rbs +9 -0
- data/sig/lib/hearth/signers/anonymous.rbs +9 -0
- data/sig/lib/hearth/signers/http_api_key.rbs +9 -0
- data/sig/lib/hearth/signers/http_basic.rbs +9 -0
- data/sig/lib/hearth/signers/http_bearer.rbs +9 -0
- data/sig/lib/hearth/signers/http_digest.rbs +9 -0
- data/sig/lib/hearth/signers.rbs +9 -0
- data/sig/lib/hearth/structure.rbs +6 -0
- data/sig/lib/hearth/stubs.rbs +9 -0
- data/sig/lib/hearth/union.rbs +5 -0
- data/sig/lib/hearth/waiters/waiter.rbs +17 -0
- data/sig/lib/hearth/xml/parse_error.rbs +9 -0
- metadata +151 -25
- data/lib/hearth/http/headers.rb +0 -70
- data/lib/hearth/middleware/around_handler.rb +0 -24
- data/lib/hearth/middleware/request_handler.rb +0 -24
- data/lib/hearth/middleware/response_handler.rb +0 -25
- data/lib/hearth/middleware_builder.rb +0 -246
- data/lib/hearth/stubbing/client_stubs.rb +0 -115
- data/lib/hearth/stubbing/stubs.rb +0 -32
- data/lib/hearth/waiters/errors.rb +0 -15
- data/sig/lib/seahorse/api_error.rbs +0 -10
- data/sig/lib/seahorse/document.rbs +0 -2
- data/sig/lib/seahorse/http/api_error.rbs +0 -21
- data/sig/lib/seahorse/http/headers.rbs +0 -47
- data/sig/lib/seahorse/http/response.rbs +0 -21
- data/sig/lib/seahorse/simple_delegator.rbs +0 -3
- data/sig/lib/seahorse/structure.rbs +0 -18
- data/sig/lib/seahorse/stubbing/client_stubs.rbs +0 -103
- data/sig/lib/seahorse/stubbing/stubs.rbs +0 -14
- data/sig/lib/seahorse/union.rbs +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a6aa5be0acf82ba6ba9b2d399c702fd0da402764dd4769cc3d72a632074dbb4
|
4
|
+
data.tar.gz: f7b14b1778860d004cb9fcea31c1fb0d230760c330447136414342f37cbd3a52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd6f92a2e98ab0942ddd68a6edb86cd4e274389c4d1595ec2ff360a6c6a7a9887a5534a58271009eef0697018bf8327b5c144cc47a541e102d57a0f3fe198be2
|
7
|
+
data.tar.gz: 7ae01e2405d9d7301ea2b9f6b8805fcd438de16d498b9e394f7e0ba5452a3acc6e681b5a32e7371b3cbe9fced1984ded25e4b16bb3512d1bf282f19079490614
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
Unreleased Changes
|
2
2
|
------------------
|
3
3
|
|
4
|
-
1.0.0.
|
4
|
+
1.0.0.pre3 (2024-05-01)
|
5
5
|
------------------
|
6
6
|
|
7
|
-
* Feature -
|
7
|
+
* Feature - Third initial public pre-release for Smithy Ruby SDKs.
|
8
|
+
|
9
|
+
1.0.0.pre2 (2023-12-19)
|
10
|
+
------------------
|
8
11
|
|
9
|
-
|
12
|
+
* Feature - Second initial public pre-release for Smithy Ruby SDKs.
|
13
|
+
|
14
|
+
1.0.0.pre1 (2022-01-10)
|
10
15
|
------------------
|
11
16
|
|
12
|
-
|
17
|
+
* Feature - Initial public pre-release for Smithy Ruby SDKs.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0.
|
1
|
+
1.0.0.pre3
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# Always returns the Anonymous/noAuth auth scheme.
|
5
|
+
# Can be used to effectively disable/skip auth.
|
6
|
+
class AnonymousAuthResolver
|
7
|
+
def resolve(_params)
|
8
|
+
[Hearth::AuthOption.new(scheme_id: 'smithy.api#noAuth')]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/hearth/api_error.rb
CHANGED
@@ -4,12 +4,26 @@ module Hearth
|
|
4
4
|
# Base class for errors returned from an API. This excludes networking
|
5
5
|
# errors and errors generated on the client-side.
|
6
6
|
class ApiError < StandardError
|
7
|
-
def initialize(error_code:, message: nil)
|
7
|
+
def initialize(error_code:, metadata: {}, message: nil)
|
8
8
|
@error_code = error_code
|
9
|
+
@metadata = metadata
|
9
10
|
super(message)
|
10
11
|
end
|
11
12
|
|
12
13
|
# @return [String]
|
13
14
|
attr_reader :error_code
|
15
|
+
|
16
|
+
# @return [Hash]
|
17
|
+
attr_reader :metadata
|
18
|
+
|
19
|
+
# @return [Boolean]
|
20
|
+
def retryable?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Boolean]
|
25
|
+
def throttling?
|
26
|
+
false
|
27
|
+
end
|
14
28
|
end
|
15
29
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# Object that represents an auth option, returned by Auth Resolvers.
|
5
|
+
class AuthOption
|
6
|
+
def initialize(scheme_id:, identity_properties: {}, signer_properties: {})
|
7
|
+
@scheme_id = scheme_id
|
8
|
+
@identity_properties = identity_properties
|
9
|
+
@signer_properties = signer_properties
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [String]
|
13
|
+
attr_reader :scheme_id
|
14
|
+
|
15
|
+
# @return [Hash]
|
16
|
+
attr_reader :identity_properties
|
17
|
+
|
18
|
+
# @return [Hash]
|
19
|
+
attr_reader :signer_properties
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module AuthSchemes
|
5
|
+
# Anonymous authentication scheme.
|
6
|
+
class Anonymous < AuthSchemes::Base
|
7
|
+
def initialize
|
8
|
+
super(
|
9
|
+
scheme_id: 'smithy.api#noAuth',
|
10
|
+
signer: Signers::Anonymous.new,
|
11
|
+
identity_type: Identities::Anonymous
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [IdentityProvider, nil]
|
16
|
+
def identity_provider(_identity_providers = {})
|
17
|
+
Hearth::IdentityProvider.new(proc { Identities::Anonymous.new })
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module AuthSchemes
|
5
|
+
# HTTP API Key authentication scheme.
|
6
|
+
class HTTPApiKey < AuthSchemes::Base
|
7
|
+
def initialize
|
8
|
+
super(
|
9
|
+
scheme_id: 'smithy.api#httpApiKeyAuth',
|
10
|
+
signer: Signers::HTTPApiKey.new,
|
11
|
+
identity_type: Identities::HTTPApiKey
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module AuthSchemes
|
5
|
+
# HTTP Basic authentication scheme.
|
6
|
+
class HTTPBasic < AuthSchemes::Base
|
7
|
+
def initialize
|
8
|
+
super(
|
9
|
+
scheme_id: 'smithy.api#httpBasicAuth',
|
10
|
+
signer: Signers::HTTPBasic.new,
|
11
|
+
identity_type: Identities::HTTPLogin
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module AuthSchemes
|
5
|
+
# HTTP Bearer authentication scheme.
|
6
|
+
class HTTPBearer < AuthSchemes::Base
|
7
|
+
def initialize
|
8
|
+
super(
|
9
|
+
scheme_id: 'smithy.api#httpBearerAuth',
|
10
|
+
signer: Signers::HTTPBearer.new,
|
11
|
+
identity_type: Identities::HTTPBearer
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module AuthSchemes
|
5
|
+
# HTTP Digest authentication scheme.
|
6
|
+
class HTTPDigest < AuthSchemes::Base
|
7
|
+
def initialize
|
8
|
+
super(
|
9
|
+
scheme_id: 'smithy.api#httpDigestAuth',
|
10
|
+
signer: Signers::HTTPDigest.new,
|
11
|
+
identity_type: Identities::HTTPLogin
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# Namespace for all AuthScheme classes.
|
5
|
+
module AuthSchemes
|
6
|
+
# Base class for all AuthScheme classes.
|
7
|
+
class Base
|
8
|
+
def initialize(scheme_id:, signer:, identity_type:)
|
9
|
+
@scheme_id = scheme_id
|
10
|
+
@signer = signer
|
11
|
+
@identity_type = identity_type
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
attr_reader :scheme_id
|
16
|
+
|
17
|
+
# @return [IdentityProvider, nil]
|
18
|
+
def identity_provider(identity_provider = {})
|
19
|
+
identity_provider[@identity_type]
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Signers::Base]
|
23
|
+
attr_reader :signer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require_relative 'auth_schemes/anonymous'
|
29
|
+
require_relative 'auth_schemes/http_api_key'
|
30
|
+
require_relative 'auth_schemes/http_basic'
|
31
|
+
require_relative 'auth_schemes/http_bearer'
|
32
|
+
require_relative 'auth_schemes/http_digest'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
module Hearth
|
6
|
+
# A utility module for calculating checksums.
|
7
|
+
# @api private
|
8
|
+
module Checksums
|
9
|
+
CHUNK_SIZE = 1 * 1024 * 1024 # one MB
|
10
|
+
|
11
|
+
# @param [File, Tempfile, StringIO#read, String] value
|
12
|
+
# @return [String<MD5>]
|
13
|
+
def self.md5(value)
|
14
|
+
if value.is_a?(File) || value.is_a?(Tempfile)
|
15
|
+
OpenSSL::Digest.new('MD5').file(value).base64digest
|
16
|
+
elsif value.respond_to?(:read)
|
17
|
+
md5 = OpenSSL::Digest.new('MD5')
|
18
|
+
loop do
|
19
|
+
chunk = value.read(CHUNK_SIZE)
|
20
|
+
break unless chunk
|
21
|
+
|
22
|
+
md5.update(chunk)
|
23
|
+
end
|
24
|
+
value.rewind
|
25
|
+
md5.base64digest
|
26
|
+
else
|
27
|
+
OpenSSL::Digest.new('MD5').base64digest(value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client_stubs'
|
4
|
+
|
5
|
+
module Hearth
|
6
|
+
# Base Client class for all generated SDK clients.
|
7
|
+
class Client
|
8
|
+
include ClientStubs
|
9
|
+
|
10
|
+
# Plugins applied to all instances of this client.
|
11
|
+
# @return [Hearth::PluginList]
|
12
|
+
def self.plugins
|
13
|
+
@plugins ||= PluginList.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [Hash] options
|
17
|
+
# Options used to construct an instance of {Config}
|
18
|
+
# @param [Class] config_class
|
19
|
+
# The configuration class to use.
|
20
|
+
def initialize(options, config_class)
|
21
|
+
@config = initialize_config(options, config_class)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Configuration]
|
25
|
+
attr_reader :config
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def initialize_config(options, config_class)
|
30
|
+
client_interceptors = options.delete(:interceptors) || []
|
31
|
+
config = config_class.new(**options)
|
32
|
+
config.validate!
|
33
|
+
self.class.plugins.each { |p| p.call(config) }
|
34
|
+
config.plugins.each { |p| p.call(config) }
|
35
|
+
config.interceptors.concat(client_interceptors)
|
36
|
+
config.validate!
|
37
|
+
config.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def operation_config(options)
|
41
|
+
return @config if options.empty?
|
42
|
+
|
43
|
+
if options.include?(:stub_responses) || options.include?(:stubs)
|
44
|
+
msg = 'Overriding stubs or stub_responses on ' \
|
45
|
+
'operations is not allowed'
|
46
|
+
raise ArgumentError, msg
|
47
|
+
end
|
48
|
+
|
49
|
+
operation_plugins = options.delete(:plugins)
|
50
|
+
operation_interceptors = options.delete(:interceptors) || []
|
51
|
+
config = @config.merge(options)
|
52
|
+
config.validate!
|
53
|
+
operation_plugins&.each { |p| p.call(config) }
|
54
|
+
config.interceptors.concat(operation_interceptors)
|
55
|
+
config.validate!
|
56
|
+
config.freeze
|
57
|
+
end
|
58
|
+
|
59
|
+
def output_stream(options = {}, &block)
|
60
|
+
return options.delete(:output_stream) if options[:output_stream]
|
61
|
+
return Hearth::BlockIO.new(block) if block
|
62
|
+
|
63
|
+
::StringIO.new
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# This module provides the ability to specify the data and/or errors to
|
5
|
+
# return when a client is using stubbed responses.
|
6
|
+
# This module should be included in generated service clients.
|
7
|
+
#
|
8
|
+
# Pass `stub_responses: true` to a Client's Config constructor
|
9
|
+
# to enable this behavior.
|
10
|
+
module ClientStubs
|
11
|
+
# Configures what data / errors should be returned from the named operation
|
12
|
+
# when response stubbing is enabled.
|
13
|
+
#
|
14
|
+
# ## Basic usage
|
15
|
+
#
|
16
|
+
# When you enable response stubbing, the client will generate fake
|
17
|
+
# responses and will not make any HTTP requests. The SDK will default
|
18
|
+
# to generate fake responses with placeholder values. You can override
|
19
|
+
# the data returned using {#stub_responses}. You can also specify errors
|
20
|
+
# (with error data) that it should raise.
|
21
|
+
#
|
22
|
+
# client = Service::Client.new(stub_responses: true)
|
23
|
+
# client.operation
|
24
|
+
# #=> #<struct Service:Types::Operation param1=[], param2=nil>
|
25
|
+
#
|
26
|
+
# You can specify the modeled stub data using the :data key.
|
27
|
+
#
|
28
|
+
# client = Service::Client.new(stub_responses: true)
|
29
|
+
# client.stub_responses(
|
30
|
+
# :operation,
|
31
|
+
# data: { param1: [{ name: 'value1' }] }
|
32
|
+
# )
|
33
|
+
# client.operation.param1.map(&:name)
|
34
|
+
# #=> ['value1']
|
35
|
+
#
|
36
|
+
# Stub data can also be provided as an output Type.
|
37
|
+
#
|
38
|
+
# client = Service::Client.new(stub_responses: true)
|
39
|
+
# output = Service::Types::OperationOutput.new(
|
40
|
+
# param1: [{ name: 'value1' }]
|
41
|
+
# )
|
42
|
+
# client.stub_responses(:operation, output)
|
43
|
+
# client.operation(param1: 'value')
|
44
|
+
# #=> #<struct Service:Types::OperationOutput ..>
|
45
|
+
#
|
46
|
+
# You can also specify modeled errors or exceptions it should raise using
|
47
|
+
# the :error key. The error hash must have a :class and optionally any
|
48
|
+
# :data to populate the error with.
|
49
|
+
#
|
50
|
+
# client = Service::Client.new(stub_responses: true)
|
51
|
+
# client.stub_responses(
|
52
|
+
# :operation,
|
53
|
+
# error: { class: ModeledError, data: { message: 'error message' } }
|
54
|
+
# )
|
55
|
+
# #=> raises ModeledError.new('error message')
|
56
|
+
#
|
57
|
+
# Constructed Exceptions will also be raised if provided.
|
58
|
+
#
|
59
|
+
# client.stub_responses(:operation, Hearth::NetworkingError.new)
|
60
|
+
# client.operation(param1: 'value')
|
61
|
+
# #=> raises Hearth::NetworkingError
|
62
|
+
#
|
63
|
+
# ## Dynamic Stubbing
|
64
|
+
#
|
65
|
+
# In addition to creating static stubs, it's also possible to generate
|
66
|
+
# stubs dynamically based on the input with which operations were
|
67
|
+
# called, by passing a `Proc` object:
|
68
|
+
#
|
69
|
+
# client.stub_responses(:operation, -> (input) {
|
70
|
+
# if input[:param] == 'foo'
|
71
|
+
# # return a data stub
|
72
|
+
# { data: { param1: [{ name: 'value1'}]} }
|
73
|
+
# else
|
74
|
+
# # return an error stub
|
75
|
+
# { error: Service::Errors::NotFound }
|
76
|
+
# end
|
77
|
+
# })
|
78
|
+
#
|
79
|
+
# ## Stubbing Raw Protocol Responses
|
80
|
+
#
|
81
|
+
# As an alternative to providing the response data, you can provide an
|
82
|
+
# instance of Hearth::Response to stub with.
|
83
|
+
#
|
84
|
+
# response = Hearth::HTTP::Response.new(
|
85
|
+
# status: 200,
|
86
|
+
# body: StringIO.new('{param1: "value1"}'),
|
87
|
+
# )
|
88
|
+
# client.stub_responses(:operation, response)
|
89
|
+
# #=> #<struct Service:Types::OperationOutput param1="value1">
|
90
|
+
#
|
91
|
+
# ## Stubbing Multiple Responses
|
92
|
+
#
|
93
|
+
# Calling an operation multiple times will return similar responses.
|
94
|
+
# You can configure multiple stubs and they will be returned in sequence.
|
95
|
+
#
|
96
|
+
# client.stub_responses(
|
97
|
+
# :operation,
|
98
|
+
# { error: Service::Errors::NotFound },
|
99
|
+
# { data: { content_length: 150 } },
|
100
|
+
# ])
|
101
|
+
#
|
102
|
+
# client.operation(param1: 'value1')
|
103
|
+
# #=> raises Service::Errors::NotFound
|
104
|
+
#
|
105
|
+
# resp = client.operation(param1: 'value2')
|
106
|
+
# resp.data.content_length #=> 150
|
107
|
+
#
|
108
|
+
# @param [Symbol] operation_name
|
109
|
+
#
|
110
|
+
# @param [Mixed] stubs One or more responses to return from the named
|
111
|
+
# operation.
|
112
|
+
#
|
113
|
+
# @return [void]
|
114
|
+
#
|
115
|
+
# @raise [RuntimeError] Raises a runtime error when called
|
116
|
+
# on a client that has not enabled response stubbing via
|
117
|
+
# `:stub_responses => true`.
|
118
|
+
def stub_responses(operation_name, *stubs)
|
119
|
+
if @config.stub_responses
|
120
|
+
@config.stubs.set_stubs(operation_name, stubs.flatten)
|
121
|
+
else
|
122
|
+
msg = 'Stubbing is not enabled. Enable stubbing in Config ' \
|
123
|
+
'with `stub_responses: true`'
|
124
|
+
raise ArgumentError, msg
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# @api private
|
5
|
+
module Config
|
6
|
+
# Parses and validates values provided in ENV
|
7
|
+
class EnvProvider
|
8
|
+
def initialize(env_key, type: 'String')
|
9
|
+
@env_key = env_key
|
10
|
+
@type = type
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(_cfg)
|
14
|
+
return unless (value = ENV.fetch(@env_key, nil))
|
15
|
+
|
16
|
+
case @type
|
17
|
+
when 'Float' then parse_float(value)
|
18
|
+
when 'Integer' then parse_integer(value)
|
19
|
+
when 'Boolean' then parse_boolean(value)
|
20
|
+
else
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def parse_float(value)
|
28
|
+
Float(value)
|
29
|
+
rescue ArgumentError
|
30
|
+
raise_error(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_integer(value)
|
34
|
+
Integer(value)
|
35
|
+
rescue ArgumentError
|
36
|
+
raise_error(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_boolean(value)
|
40
|
+
case value.downcase
|
41
|
+
when 'true' then true
|
42
|
+
when 'false' then false
|
43
|
+
else raise_error(value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def raise_error(value)
|
48
|
+
raise ArgumentError,
|
49
|
+
"Expected ENV['#{@env_key}'] to be a #{@type}, got #{value}."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# @api private
|
5
|
+
module Config
|
6
|
+
# Resolves configuration options.
|
7
|
+
class Resolver
|
8
|
+
private_class_method :new
|
9
|
+
|
10
|
+
# @param config [Struct]
|
11
|
+
# @param options [Hash]
|
12
|
+
# @param defaults [Hash<Array<Proc>>]
|
13
|
+
# @return [Struct]
|
14
|
+
def self.resolve(config, options, defaults = {})
|
15
|
+
new(config).send(:resolve, options, defaults)
|
16
|
+
end
|
17
|
+
|
18
|
+
def key(key)
|
19
|
+
@options[key] = resolve_default(key) unless @options.key?(key)
|
20
|
+
@options[key]
|
21
|
+
end
|
22
|
+
alias [] key
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# @param config [Struct]
|
27
|
+
def initialize(config)
|
28
|
+
@config = config
|
29
|
+
end
|
30
|
+
|
31
|
+
def resolve(options, defaults)
|
32
|
+
@options = options
|
33
|
+
@defaults = defaults
|
34
|
+
@config.members.each do |key|
|
35
|
+
@config[key] = key(key)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def resolve_default(key)
|
40
|
+
@defaults[key]&.each do |default|
|
41
|
+
value =
|
42
|
+
if default.respond_to?(:call)
|
43
|
+
default.call(self)
|
44
|
+
else
|
45
|
+
default
|
46
|
+
end
|
47
|
+
return value unless value.nil?
|
48
|
+
end
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# A module mixed into Config structs that resolves default value providers.
|
5
|
+
module Configuration
|
6
|
+
def initialize(**options)
|
7
|
+
Hearth::Config::Resolver.resolve(self, options, defaults)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def merge(configuration)
|
12
|
+
self.class.new(**to_h.merge(configuration.to_h))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
# @api private
|
5
|
+
class ConnectionPool
|
6
|
+
@pools_mutex = Mutex.new
|
7
|
+
@pools = {}
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# @return [ConnectionPool]
|
11
|
+
def for(config = {})
|
12
|
+
@pools_mutex.synchronize do
|
13
|
+
@pools[config] ||= new
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Array<ConnectionPool>] Returns a list of the
|
18
|
+
# constructed connection pools.
|
19
|
+
def pools
|
20
|
+
@pools_mutex.synchronize do
|
21
|
+
@pools.values
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def initialize
|
28
|
+
@pool_mutex = Mutex.new
|
29
|
+
@pool = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param [URI::HTTP, URI::HTTPS] endpoint The HTTP(S) endpoint
|
33
|
+
# to connect to (e.g. 'https://domain.com').
|
34
|
+
# @param [Proc] block A block that returns a new connection if
|
35
|
+
# there are no connections present.
|
36
|
+
# @return [Connection, nil]
|
37
|
+
def connection_for(endpoint, &block)
|
38
|
+
connection = nil
|
39
|
+
endpoint = remove_path_and_query(endpoint)
|
40
|
+
# attempt to recycle an already open connection
|
41
|
+
@pool_mutex.synchronize do
|
42
|
+
clean
|
43
|
+
connection = @pool[endpoint].shift if @pool.key?(endpoint)
|
44
|
+
end
|
45
|
+
connection || (block.call if block_given?)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param [URI::HTTP, URI::HTTPS] endpoint The HTTP(S) endpoint
|
49
|
+
# @param [Object] connection The connection to check back into the pool.
|
50
|
+
# @return [nil]
|
51
|
+
def offer(endpoint, connection)
|
52
|
+
endpoint = remove_path_and_query(endpoint)
|
53
|
+
@pool_mutex.synchronize do
|
54
|
+
@pool[endpoint] = [] unless @pool.key?(endpoint)
|
55
|
+
@pool[endpoint] << connection
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Removes stale connections from the pool. This method *must* be called
|
62
|
+
# @note **Must** be called behind a `@pool_mutex` synchronize block.
|
63
|
+
def clean
|
64
|
+
@pool.each_pair do |_endpoint, connections|
|
65
|
+
connections.delete_if(&:stale?)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Connection pools should be keyed by endpoint and port.
|
70
|
+
def remove_path_and_query(endpoint)
|
71
|
+
endpoint.dup.tap do |e|
|
72
|
+
e.path = ''
|
73
|
+
e.query = nil
|
74
|
+
end.to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|