aws-sdk-core 3.46.2 → 3.47.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/aws-sdk-core.rb +1 -0
  4. data/lib/aws-sdk-core/async_client_stubs.rb +80 -0
  5. data/lib/aws-sdk-core/binary.rb +3 -0
  6. data/lib/aws-sdk-core/binary/decode_handler.rb +21 -1
  7. data/lib/aws-sdk-core/binary/encode_handler.rb +32 -0
  8. data/lib/aws-sdk-core/binary/event_builder.rb +122 -0
  9. data/lib/aws-sdk-core/binary/event_parser.rb +48 -18
  10. data/lib/aws-sdk-core/binary/event_stream_decoder.rb +5 -2
  11. data/lib/aws-sdk-core/binary/event_stream_encoder.rb +53 -0
  12. data/lib/aws-sdk-core/client_stubs.rb +1 -1
  13. data/lib/aws-sdk-core/errors.rb +4 -0
  14. data/lib/aws-sdk-core/event_emitter.rb +42 -0
  15. data/lib/aws-sdk-core/json/handler.rb +19 -1
  16. data/lib/aws-sdk-core/param_validator.rb +9 -1
  17. data/lib/aws-sdk-core/plugins/event_stream_configuration.rb +14 -0
  18. data/lib/aws-sdk-core/plugins/invocation_id.rb +33 -0
  19. data/lib/aws-sdk-core/plugins/stub_responses.rb +19 -7
  20. data/lib/aws-sdk-core/stubbing/protocols/rest.rb +19 -0
  21. data/lib/aws-sdk-core/stubbing/stub_data.rb +1 -1
  22. data/lib/aws-sdk-sts.rb +1 -1
  23. data/lib/aws-sdk-sts/client.rb +1 -1
  24. data/lib/seahorse.rb +9 -0
  25. data/lib/seahorse/client/async_base.rb +50 -0
  26. data/lib/seahorse/client/async_response.rb +73 -0
  27. data/lib/seahorse/client/base.rb +1 -1
  28. data/lib/seahorse/client/h2/connection.rb +242 -0
  29. data/lib/seahorse/client/h2/handler.rb +149 -0
  30. data/lib/seahorse/client/http/async_response.rb +42 -0
  31. data/lib/seahorse/client/http/response.rb +10 -5
  32. data/lib/seahorse/client/networking_error.rb +28 -0
  33. data/lib/seahorse/client/plugins/h2.rb +64 -0
  34. data/lib/seahorse/model/api.rb +4 -0
  35. data/lib/seahorse/model/operation.rb +4 -0
  36. metadata +35 -4
@@ -291,7 +291,7 @@ module Aws
291
291
  def data_to_http_resp(operation_name, data)
292
292
  api = config.api
293
293
  operation = api.operation(operation_name)
294
- ParamValidator.validate!(operation.output, data)
294
+ ParamValidator.new(operation.output, input: false).validate!(data)
295
295
  protocol_helper.stub_data(api, operation, data)
296
296
  end
297
297
 
@@ -62,6 +62,10 @@ module Aws
62
62
  # a raw event message
63
63
  class EventStreamParserError < RuntimeError; end
64
64
 
65
+ # Raise when EventStream Builder failed to build
66
+ # an event message with parameters provided
67
+ class EventStreamBuilderError < RuntimeError; end
68
+
65
69
  # Error event in an event stream which has event_type :error
66
70
  # error code and error message can be retrieved when available.
67
71
  #
@@ -3,8 +3,18 @@ module Aws
3
3
 
4
4
  def initialize
5
5
  @listeners = {}
6
+ @validate_event = true
7
+ @buffer = Queue.new
6
8
  end
7
9
 
10
+ attr_accessor :stream
11
+
12
+ attr_accessor :encoder
13
+
14
+ attr_accessor :validate_event
15
+
16
+ attr_reader :buffer
17
+
8
18
  def on(type, callback)
9
19
  (@listeners[type] ||= []) << callback
10
20
  end
@@ -16,5 +26,37 @@ module Aws
16
26
  end
17
27
  end
18
28
 
29
+ def emit(type, params)
30
+ @buffer << Proc.new do
31
+ if @validate_event && type != :end_stream
32
+ Aws::ParamValidator.validate!(
33
+ @encoder.rules.shape.member(type), params)
34
+ end
35
+ @stream.data(
36
+ @encoder.encode(type, params),
37
+ end_stream: type == :end_stream
38
+ )
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ class Queue
45
+
46
+ def initialize(procs = [])
47
+ @procs = procs
48
+ @mutex = Mutex.new
49
+ end
50
+
51
+ def <<(callback)
52
+ @mutex.synchronize { @procs << callback }
53
+ end
54
+
55
+ def shift
56
+ @mutex.synchronize { @procs.shift }
57
+ end
58
+
59
+ end
60
+
19
61
  end
20
62
  end
@@ -40,7 +40,25 @@ module Aws
40
40
  Json.load(context.http_response.body_contents)
41
41
  elsif rules = context.operation.output
42
42
  json = context.http_response.body_contents
43
- Parser.new(rules).parse(json == '' ? '{}' : json)
43
+ if json.is_a?(Array)
44
+ # an array of emitted events
45
+ if json[0].respond_to?(:response)
46
+ # initial response exists
47
+ # it must be the first event arrived
48
+ resp_struct = json.shift.response
49
+ else
50
+ resp_struct = context.operation.output.shape.struct_class.new
51
+ end
52
+
53
+ rules.shape.members.each do |name, ref|
54
+ if ref.eventstream
55
+ resp_struct.send("#{name}=", json.to_enum)
56
+ end
57
+ end
58
+ resp_struct
59
+ else
60
+ Parser.new(rules).parse(json == '' ? '{}' : json)
61
+ end
44
62
  else
45
63
  EmptyStructure.new
46
64
  end
@@ -22,6 +22,7 @@ module Aws
22
22
  ShapeRef.new(shape: shape)
23
23
  end
24
24
  @validate_required = options[:validate_required] != false
25
+ @input = options[:input].nil? ? true : !!options[:input]
25
26
  end
26
27
 
27
28
  # @param [Hash] params
@@ -39,6 +40,7 @@ module Aws
39
40
  return unless correct_type?(ref, values, errors, context)
40
41
 
41
42
  if ref.eventstream
43
+ # input eventstream is provided from event signals
42
44
  values.each do |value|
43
45
  # each event is structure type
44
46
  case value[:message_type]
@@ -58,7 +60,8 @@ module Aws
58
60
  # ensure required members are present
59
61
  if @validate_required
60
62
  shape.required.each do |member_name|
61
- if values[member_name].nil?
63
+ input_eventstream = ref.shape.member(member_name).eventstream && @input
64
+ if values[member_name].nil? && !input_eventstream
62
65
  param = "#{context}[#{member_name.inspect}]"
63
66
  errors << "missing required parameter #{param}"
64
67
  end
@@ -147,6 +150,11 @@ module Aws
147
150
  end
148
151
 
149
152
  def correct_type?(ref, value, errors, context)
153
+ if ref.eventstream && @input
154
+ errors << "instead of providing value directly for eventstreams at input,"\
155
+ " expected to use #signal events per stream"
156
+ return false
157
+ end
150
158
  case value
151
159
  when Hash then true
152
160
  when ref.shape.struct_class then true
@@ -10,6 +10,20 @@ module Aws
10
10
  When an EventStream or Proc object is provided, it will be used as callback for each chunk of event stream response received along the way.
11
11
  DOCS
12
12
 
13
+ option(:input_event_stream_handler,
14
+ default: nil,
15
+ doc_type: 'Proc',
16
+ docstring: <<-DOCS)
17
+ When an EventStream or Proc object is provided, it can be used for sending events for the event stream.
18
+ DOCS
19
+
20
+ option(:output_event_stream_handler,
21
+ default: nil,
22
+ doc_type: 'Proc',
23
+ docstring: <<-DOCS)
24
+ When an EventStream or Proc object is provided, it will be used as callback for each chunk of event stream response received along the way.
25
+ DOCS
26
+
13
27
  end
14
28
 
15
29
  end
@@ -0,0 +1,33 @@
1
+ require 'securerandom'
2
+
3
+ module Aws
4
+ module Plugins
5
+
6
+ # @api private
7
+ class InvocationId < Seahorse::Client::Plugin
8
+
9
+ # @api private
10
+ class Handler < Seahorse::Client::Handler
11
+
12
+ def call(context)
13
+ apply_invocation_id(context)
14
+ @handler.call(context)
15
+ end
16
+
17
+ private
18
+
19
+ def apply_invocation_id(context)
20
+ context.http_request.headers['amz-sdk-invocation-id'] = SecureRandom.uuid
21
+ if context[:input_event_emitter]
22
+ # only used for eventstreaming at input
23
+ context.http_request.headers['x-amz-content-sha256'] = 'STREAMING-AWS4-HMAC-SHA256-EVENTS'
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ handler(Handler, step: :initialize)
30
+
31
+ end
32
+ end
33
+ end
@@ -45,15 +45,18 @@ requests are made, and retries are disabled.
45
45
  def call(context)
46
46
  stub = context.client.next_stub(context)
47
47
  resp = Seahorse::Client::Response.new(context: context)
48
- apply_stub(stub, resp)
49
- resp
48
+ async_mode = context.client.is_a? Seahorse::Client::AsyncBase
49
+ apply_stub(stub, resp, async_mode)
50
+
51
+ async_mode ? Seahorse::Client::AsyncResponse.new(
52
+ context: context, stream: context[:input_event_stream_handler].event_emitter.stream, sync_queue: Queue.new) : resp
50
53
  end
51
54
 
52
- def apply_stub(stub, response)
55
+ def apply_stub(stub, response, async_mode = false)
53
56
  http_resp = response.context.http_response
54
57
  case
55
58
  when stub[:error] then signal_error(stub[:error], http_resp)
56
- when stub[:http] then signal_http(stub[:http], http_resp)
59
+ when stub[:http] then signal_http(stub[:http], http_resp, async_mode)
57
60
  when stub[:data] then response.data = stub[:data]
58
61
  end
59
62
  end
@@ -67,9 +70,18 @@ requests are made, and retries are disabled.
67
70
  end
68
71
 
69
72
  # @param [Seahorse::Client::Http::Response] stub
70
- # @param [Seahorse::Client::Http::Response] http_resp
71
- def signal_http(stub, http_resp)
72
- http_resp.signal_headers(stub.status_code, stub.headers.to_h)
73
+ # @param [Seahorse::Client::Http::Response | Seahorse::Client::Http::AsyncResponse] http_resp
74
+ # @param [Boolean] async_mode
75
+ def signal_http(stub, http_resp, async_mode = false)
76
+ if async_mode
77
+ h2_headers = stub.headers.to_h.inject([]) do |arr, (k, v)|
78
+ arr << [k, v]
79
+ end
80
+ h2_headers << [":status", stub.status_code]
81
+ http_resp.signal_headers(h2_headers)
82
+ else
83
+ http_resp.signal_headers(stub.status_code, stub.headers.to_h)
84
+ end
73
85
  while chunk = stub.body.read(1024 * 1024)
74
86
  http_resp.signal_data(chunk)
75
87
  end
@@ -118,6 +118,25 @@ module Aws
118
118
 
119
119
  def encode_event(opts, rules, event_data, builder)
120
120
  event_ref = rules.shape.member(event_data.delete(:event_type))
121
+ explicit_payload = false
122
+ implicit_payload_members = {}
123
+ event_ref.shape.members.each do |name, ref|
124
+ if ref.eventpayload
125
+ explicit_payload = true
126
+ else
127
+ implicit_payload_members[name] = ref
128
+ end
129
+ end
130
+
131
+ if !explicit_payload && !implicit_payload_members.empty?
132
+ unless implicit_payload_members.size > 1
133
+ m_name, _ = implicit_payload_members.first
134
+ value = {}
135
+ value[m_name] = event_data[m_name]
136
+ opts[:payload] = StringIO.new(builder.new(event_ref).serialize(value))
137
+ end
138
+ end
139
+
121
140
  event_data.each do |k, v|
122
141
  member_ref = event_ref.shape.member(k)
123
142
  if member_ref.eventheader
@@ -30,7 +30,7 @@ module Aws
30
30
  end
31
31
 
32
32
  def apply_data(data, stub)
33
- ParamValidator.new(@rules, validate_required:false).validate!(data)
33
+ ParamValidator.new(@rules, validate_required: false, input: false).validate!(data)
34
34
  DataApplicator.new(@rules).apply_data(data, stub)
35
35
  end
36
36
  end
@@ -40,6 +40,6 @@ require_relative 'aws-sdk-sts/customizations'
40
40
  # @service
41
41
  module Aws::STS
42
42
 
43
- GEM_VERSION = '3.46.2'
43
+ GEM_VERSION = '3.47.0'
44
44
 
45
45
  end
@@ -1535,7 +1535,7 @@ module Aws::STS
1535
1535
  params: params,
1536
1536
  config: config)
1537
1537
  context[:gem_name] = 'aws-sdk-core'
1538
- context[:gem_version] = '3.46.2'
1538
+ context[:gem_version] = '3.47.0'
1539
1539
  Seahorse::Client::Request.new(handlers, context)
1540
1540
  end
1541
1541
 
@@ -15,12 +15,14 @@ require_relative 'seahorse/client/plugin_list'
15
15
  require_relative 'seahorse/client/request'
16
16
  require_relative 'seahorse/client/request_context'
17
17
  require_relative 'seahorse/client/response'
18
+ require_relative 'seahorse/client/async_response'
18
19
 
19
20
  # client http
20
21
 
21
22
  require_relative 'seahorse/client/http/headers'
22
23
  require_relative 'seahorse/client/http/request'
23
24
  require_relative 'seahorse/client/http/response'
25
+ require_relative 'seahorse/client/http/async_response'
24
26
 
25
27
  # client logging
26
28
 
@@ -32,12 +34,18 @@ require_relative 'seahorse/client/logging/formatter'
32
34
  require_relative 'seahorse/client/net_http/connection_pool'
33
35
  require_relative 'seahorse/client/net_http/handler'
34
36
 
37
+ # http2 handler
38
+
39
+ require_relative 'seahorse/client/h2/connection'
40
+ require_relative 'seahorse/client/h2/handler'
41
+
35
42
  # plugins
36
43
 
37
44
  require_relative 'seahorse/client/plugins/content_length'
38
45
  require_relative 'seahorse/client/plugins/endpoint'
39
46
  require_relative 'seahorse/client/plugins/logging'
40
47
  require_relative 'seahorse/client/plugins/net_http'
48
+ require_relative 'seahorse/client/plugins/h2'
41
49
  require_relative 'seahorse/client/plugins/raise_response_errors'
42
50
  require_relative 'seahorse/client/plugins/response_target'
43
51
 
@@ -49,3 +57,4 @@ require_relative 'seahorse/model/authorizer'
49
57
  require_relative 'seahorse/model/shapes'
50
58
 
51
59
  require_relative 'seahorse/client/base'
60
+ require_relative 'seahorse/client/async_base'
@@ -0,0 +1,50 @@
1
+ module Seahorse
2
+ module Client
3
+ class AsyncBase < Seahorse::Client::Base
4
+
5
+ # default H2 plugins
6
+ @plugins = PluginList.new([
7
+ Plugins::Endpoint,
8
+ Plugins::H2,
9
+ Plugins::ResponseTarget
10
+ ])
11
+
12
+ def initialize(plugins, options)
13
+ super
14
+ @connection = H2::Connection.new(options)
15
+ @options = options
16
+ end
17
+
18
+ # @return [H2::Connection]
19
+ attr_reader :connection
20
+
21
+ # @return [Array<Symbol>] Returns a list of valid async request
22
+ # operation names.
23
+ def operation_names
24
+ self.class.api.async_operation_names
25
+ end
26
+
27
+ # Closes the underlying HTTP2 Connection for the client
28
+ # @return [Symbol] Returns the status of the connection (:closed)
29
+ def close_connection
30
+ @connection.close!
31
+ end
32
+
33
+ # Creates a new HTTP2 Connection for the client
34
+ # @return [Seahorse::Client::H2::Connection]
35
+ def new_connection
36
+ if @connection.closed?
37
+ @connection = H2::Connection.new(@options)
38
+ else
39
+ @connection
40
+ end
41
+ end
42
+
43
+ def connection_errors
44
+ @connection.errors
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,73 @@
1
+ module Seahorse
2
+ module Client
3
+ class AsyncResponse
4
+
5
+ def initialize(options = {})
6
+ @response = Response.new(context: options[:context])
7
+ @stream = options[:stream]
8
+ @stream_mutex = options[:stream_mutex]
9
+ @close_condition = options[:close_condition]
10
+ @sync_queue = options[:sync_queue]
11
+ end
12
+
13
+ def context
14
+ @response.context
15
+ end
16
+
17
+ def error
18
+ @response.error
19
+ end
20
+
21
+ def on(range, &block)
22
+ @response.on(range, &block)
23
+ self
24
+ end
25
+
26
+ def on_complete(&block)
27
+ @response.on_complete(&block)
28
+ self
29
+ end
30
+
31
+ def wait
32
+ if error && context.config.raise_response_errors
33
+ raise error
34
+ elsif @stream
35
+ # have a sync signal that #signal can be blocked on
36
+ # else, if #signal is called before #wait
37
+ # will be waiting for a signal never arrives
38
+ @sync_queue << "sync_signal"
39
+ # now #signal is unlocked for
40
+ # signaling close condition when ready
41
+ @stream_mutex.synchronize {
42
+ @close_condition.wait(@stream_mutex)
43
+ }
44
+ _kill_input_thread
45
+ @response
46
+ end
47
+ end
48
+
49
+ def join!
50
+ if error && context.config.raise_response_errors
51
+ raise error
52
+ elsif @stream
53
+ # close callback is waiting
54
+ # for the "sync_signal"
55
+ @sync_queue << "sync_signal"
56
+ @stream.close
57
+ _kill_input_thread
58
+ @response
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def _kill_input_thread
65
+ if thread = context[:input_signal_thread]
66
+ Thread.kill(thread)
67
+ end
68
+ nil
69
+ end
70
+
71
+ end
72
+ end
73
+ end