mss-sdk 1.0.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 (131) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/LICENSE.txt +0 -0
  4. data/README.md +192 -0
  5. data/bin/mss-rb +178 -0
  6. data/ca-bundle.crt +3554 -0
  7. data/lib/mss/core/async_handle.rb +89 -0
  8. data/lib/mss/core/cacheable.rb +76 -0
  9. data/lib/mss/core/client.rb +786 -0
  10. data/lib/mss/core/collection/simple.rb +81 -0
  11. data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
  12. data/lib/mss/core/collection/with_next_token.rb +96 -0
  13. data/lib/mss/core/collection.rb +262 -0
  14. data/lib/mss/core/configuration.rb +527 -0
  15. data/lib/mss/core/credential_providers.rb +653 -0
  16. data/lib/mss/core/data.rb +251 -0
  17. data/lib/mss/core/deprecations.rb +83 -0
  18. data/lib/mss/core/endpoints.rb +36 -0
  19. data/lib/mss/core/http/connection_pool.rb +374 -0
  20. data/lib/mss/core/http/curb_handler.rb +150 -0
  21. data/lib/mss/core/http/handler.rb +88 -0
  22. data/lib/mss/core/http/net_http_handler.rb +144 -0
  23. data/lib/mss/core/http/patch.rb +98 -0
  24. data/lib/mss/core/http/request.rb +258 -0
  25. data/lib/mss/core/http/response.rb +80 -0
  26. data/lib/mss/core/indifferent_hash.rb +87 -0
  27. data/lib/mss/core/inflection.rb +55 -0
  28. data/lib/mss/core/ini_parser.rb +41 -0
  29. data/lib/mss/core/json_client.rb +46 -0
  30. data/lib/mss/core/json_parser.rb +75 -0
  31. data/lib/mss/core/json_request_builder.rb +34 -0
  32. data/lib/mss/core/json_response_parser.rb +78 -0
  33. data/lib/mss/core/lazy_error_classes.rb +107 -0
  34. data/lib/mss/core/log_formatter.rb +426 -0
  35. data/lib/mss/core/managed_file.rb +31 -0
  36. data/lib/mss/core/meta_utils.rb +44 -0
  37. data/lib/mss/core/model.rb +61 -0
  38. data/lib/mss/core/naming.rb +29 -0
  39. data/lib/mss/core/option_grammar.rb +737 -0
  40. data/lib/mss/core/options/json_serializer.rb +81 -0
  41. data/lib/mss/core/options/validator.rb +154 -0
  42. data/lib/mss/core/options/xml_serializer.rb +117 -0
  43. data/lib/mss/core/page_result.rb +74 -0
  44. data/lib/mss/core/policy.rb +938 -0
  45. data/lib/mss/core/query_client.rb +40 -0
  46. data/lib/mss/core/query_error_parser.rb +23 -0
  47. data/lib/mss/core/query_request_builder.rb +46 -0
  48. data/lib/mss/core/query_response_parser.rb +34 -0
  49. data/lib/mss/core/region.rb +84 -0
  50. data/lib/mss/core/region_collection.rb +79 -0
  51. data/lib/mss/core/resource.rb +412 -0
  52. data/lib/mss/core/resource_cache.rb +39 -0
  53. data/lib/mss/core/response.rb +214 -0
  54. data/lib/mss/core/response_cache.rb +49 -0
  55. data/lib/mss/core/rest_error_parser.rb +23 -0
  56. data/lib/mss/core/rest_json_client.rb +39 -0
  57. data/lib/mss/core/rest_request_builder.rb +153 -0
  58. data/lib/mss/core/rest_response_parser.rb +65 -0
  59. data/lib/mss/core/rest_xml_client.rb +46 -0
  60. data/lib/mss/core/service_interface.rb +82 -0
  61. data/lib/mss/core/signers/base.rb +45 -0
  62. data/lib/mss/core/signers/cloud_front.rb +55 -0
  63. data/lib/mss/core/signers/s3.rb +158 -0
  64. data/lib/mss/core/signers/version_2.rb +71 -0
  65. data/lib/mss/core/signers/version_3.rb +85 -0
  66. data/lib/mss/core/signers/version_3_https.rb +60 -0
  67. data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
  68. data/lib/mss/core/signers/version_4.rb +227 -0
  69. data/lib/mss/core/uri_escape.rb +43 -0
  70. data/lib/mss/core/xml/frame.rb +245 -0
  71. data/lib/mss/core/xml/frame_stack.rb +84 -0
  72. data/lib/mss/core/xml/grammar.rb +306 -0
  73. data/lib/mss/core/xml/parser.rb +69 -0
  74. data/lib/mss/core/xml/root_frame.rb +64 -0
  75. data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
  76. data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
  77. data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
  78. data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
  79. data/lib/mss/core/xml/stub.rb +122 -0
  80. data/lib/mss/core.rb +602 -0
  81. data/lib/mss/errors.rb +161 -0
  82. data/lib/mss/rails.rb +194 -0
  83. data/lib/mss/s3/access_control_list.rb +262 -0
  84. data/lib/mss/s3/acl_object.rb +263 -0
  85. data/lib/mss/s3/acl_options.rb +200 -0
  86. data/lib/mss/s3/bucket.rb +757 -0
  87. data/lib/mss/s3/bucket_collection.rb +161 -0
  88. data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
  89. data/lib/mss/s3/bucket_region_cache.rb +51 -0
  90. data/lib/mss/s3/bucket_tag_collection.rb +110 -0
  91. data/lib/mss/s3/bucket_version_collection.rb +78 -0
  92. data/lib/mss/s3/cipher_io.rb +119 -0
  93. data/lib/mss/s3/client/xml.rb +265 -0
  94. data/lib/mss/s3/client.rb +2076 -0
  95. data/lib/mss/s3/config.rb +60 -0
  96. data/lib/mss/s3/cors_rule.rb +107 -0
  97. data/lib/mss/s3/cors_rule_collection.rb +193 -0
  98. data/lib/mss/s3/data_options.rb +190 -0
  99. data/lib/mss/s3/encryption_utils.rb +145 -0
  100. data/lib/mss/s3/errors.rb +93 -0
  101. data/lib/mss/s3/multipart_upload.rb +353 -0
  102. data/lib/mss/s3/multipart_upload_collection.rb +75 -0
  103. data/lib/mss/s3/object_collection.rb +355 -0
  104. data/lib/mss/s3/object_metadata.rb +102 -0
  105. data/lib/mss/s3/object_upload_collection.rb +76 -0
  106. data/lib/mss/s3/object_version.rb +153 -0
  107. data/lib/mss/s3/object_version_collection.rb +88 -0
  108. data/lib/mss/s3/paginated_collection.rb +74 -0
  109. data/lib/mss/s3/policy.rb +73 -0
  110. data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
  111. data/lib/mss/s3/prefixed_collection.rb +84 -0
  112. data/lib/mss/s3/presign_v4.rb +135 -0
  113. data/lib/mss/s3/presigned_post.rb +574 -0
  114. data/lib/mss/s3/region_detection.rb +75 -0
  115. data/lib/mss/s3/request.rb +61 -0
  116. data/lib/mss/s3/s3_object.rb +1795 -0
  117. data/lib/mss/s3/tree/branch_node.rb +67 -0
  118. data/lib/mss/s3/tree/child_collection.rb +103 -0
  119. data/lib/mss/s3/tree/leaf_node.rb +93 -0
  120. data/lib/mss/s3/tree/node.rb +21 -0
  121. data/lib/mss/s3/tree/parent.rb +86 -0
  122. data/lib/mss/s3/tree.rb +115 -0
  123. data/lib/mss/s3/uploaded_part.rb +81 -0
  124. data/lib/mss/s3/uploaded_part_collection.rb +83 -0
  125. data/lib/mss/s3/website_configuration.rb +101 -0
  126. data/lib/mss/s3.rb +161 -0
  127. data/lib/mss/version.rb +16 -0
  128. data/lib/mss-sdk.rb +2 -0
  129. data/lib/mss.rb +14 -0
  130. data/rails/init.rb +14 -0
  131. metadata +201 -0
@@ -0,0 +1,412 @@
1
+
2
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
5
+ # may not use this file except in compliance with the License. A copy of
6
+ # the License is located at
7
+ #
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ module MSS
15
+ module Core
16
+
17
+ # @api private
18
+ class Resource
19
+
20
+ include Model
21
+ include Cacheable
22
+
23
+ # @api private
24
+ class NotFound < StandardError; end
25
+
26
+ # @api private
27
+ def initialize *args
28
+
29
+ super
30
+
31
+ # cache static attributes passed into options
32
+
33
+ options = args.last.is_a?(Hash) ? args.last : {}
34
+ options.each_pair do |opt_name,opt_value|
35
+ if
36
+ self.class.attributes.has_key?(opt_name) and
37
+ self.class.attributes[opt_name].static?
38
+ then
39
+ static_attributes[opt_name] = opt_value
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ # @return [String] Returns a simple string representation of this resource.
46
+ def inspect
47
+
48
+ identifiers = []
49
+ resource_identifiers.each do |key, value|
50
+ if attr = self.class.attributes.values.find{|a| a.from == key }
51
+ identifiers << "#{attr.name}:#{value}"
52
+ else
53
+ identifiers << "#{key}:#{value}"
54
+ end
55
+ end
56
+
57
+ "<#{self::class} #{identifiers.join(' ')}>"
58
+
59
+ end
60
+
61
+ # @return [Boolean] Returns true if the objects references the same
62
+ # MSS resource.
63
+ def eql? other
64
+ other.kind_of?(self.class) and
65
+ other.resource_identifiers == resource_identifiers
66
+ end
67
+ alias_method :==, :eql?
68
+
69
+ # @api private
70
+ protected
71
+ def get_resource attr_name
72
+ raise NotImplementedError
73
+ end
74
+
75
+ # @api private
76
+ protected
77
+ def update_resource attr, value
78
+ raise NotImplementedError
79
+ end
80
+
81
+ # Overide this method is subclasses of Resource. This method should
82
+ # return an array of identifying key/value pairs.
83
+ #
84
+ # # @api private
85
+ # protected
86
+ # def resource_identifiers
87
+ # [[:user_name, name]]
88
+ # end
89
+ #
90
+ # @api private
91
+ protected
92
+ def resource_identifiers
93
+ raise NotImplementedError
94
+ end
95
+
96
+ # @protected
97
+ protected
98
+ def resource_options(additional = {})
99
+ Hash[resource_identifiers].merge(additional)
100
+ end
101
+
102
+ # @api private
103
+ protected
104
+ def local_cache_key
105
+ resource_identifiers.collect{|name,value| value.to_s }.join(":")
106
+ end
107
+
108
+ # @api private
109
+ protected
110
+ def static_attributes
111
+ @static_attributes ||= {}
112
+ end
113
+
114
+ # @api private
115
+ protected
116
+ def ruby_name
117
+ @ruby_name ||= Inflection.ruby_name(self.class.name)
118
+ end
119
+
120
+ # @api private
121
+ public
122
+ def attributes_from_response resp
123
+
124
+ # check each provider for this request type to see if it
125
+ # can find the resource and some of its attributes
126
+ attributes = []
127
+ self.class.attribute_providers_for(resp.request_type).each do |provider|
128
+ attributes << provider.attributes_from_response(self, resp)
129
+ end
130
+
131
+ # drop out those that returned no attributesj
132
+ attributes.compact!
133
+
134
+ # stop here if nothing was found for this resource
135
+ return nil if attributes.empty?
136
+
137
+ # merge the attributes together into a single hash
138
+ attributes = attributes.inject({}) {|hash,attribs| hash.merge(attribs) }
139
+
140
+ # cache static attributes
141
+ attributes.each_pair do |attr_name,value|
142
+ if self.class.attributes[attr_name].static?
143
+ static_attributes[attr_name] = value
144
+ end
145
+ end
146
+
147
+ attributes
148
+
149
+ end
150
+
151
+ # @api private
152
+ protected
153
+ def cache_static_attributes request_type, resp_obj
154
+ self.class.attribute_providers_for(request_type).each do |provider|
155
+ attributes = provider.attributes_from_response_object(resp_obj)
156
+ attributes.each_pair do |attr_name,value|
157
+ if self.class.attributes[attr_name].static?
158
+ static_attributes[attr_name] = value
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ class << self
165
+
166
+ # @api private
167
+ def define_attribute_type type_name
168
+ class_eval <<-METHODS
169
+
170
+ def self.#{type_name}_attributes
171
+ @#{type_name}_attributes ||= {}
172
+ end
173
+
174
+ def self.#{type_name}_attribute name, options = {}, &block
175
+ attr = attribute(name, options, &block)
176
+ #{type_name}_attributes[attr.name] = attr
177
+ end
178
+
179
+ METHODS
180
+ end
181
+
182
+ # @api private
183
+ def new_from request_type, resp_obj, *args
184
+ resource = new(*args)
185
+ resource.send(:cache_static_attributes, request_type, resp_obj)
186
+ resource
187
+ end
188
+
189
+ # @api private
190
+ def attributes
191
+ @attributes ||= Hash.new do |hash,attr_name|
192
+ raise "uknown attribute #{attr_name}"
193
+ end
194
+ end
195
+
196
+ # @api private
197
+ def attribute_providers
198
+ @attribute_providers ||= []
199
+ end
200
+
201
+ # @api private
202
+ def attribute_providers_for request_type
203
+ attribute_providers.select do |provider|
204
+ provider.request_types.include?(request_type)
205
+ end
206
+ end
207
+
208
+ # @api private
209
+ protected
210
+ def attribute name, options = {}, &block
211
+ attr = Attribute.new(name, options)
212
+ attr.instance_eval(&block) if block_given?
213
+ define_attribute_getter(attr)
214
+ define_attribute_setter(attr) if attr.mutable?
215
+ alias_method(options[:alias], name) if options[:alias]
216
+ attributes[attr.name] = attr
217
+ end
218
+
219
+ # @api private
220
+ protected
221
+ def mutable_attribute name, options = {}, &block
222
+ attribute(name, options.merge(:mutable => true), &block)
223
+ end
224
+
225
+ # @api private
226
+ protected
227
+ def define_attribute_getter attribute
228
+ define_method(attribute.name) do
229
+
230
+ return static_attributes[attribute.name] if
231
+ static_attributes.has_key?(attribute.name)
232
+
233
+ begin
234
+ retrieve_attribute(attribute) { get_resource(attribute) }
235
+ rescue Cacheable::NoData => e
236
+ name = ruby_name.tr("_", " ")
237
+ raise NotFound, "unable to find the #{name}"
238
+ end
239
+
240
+ end
241
+ end
242
+
243
+ # @api private
244
+ protected
245
+ def define_attribute_setter attribute
246
+ setter = attribute.name.to_s.sub(/\?/, '') + '='
247
+ define_method(setter) do |value|
248
+ translated_value = attribute.translate_input_value(value)
249
+ update_resource(attribute, translated_value)
250
+ if attribute.static?
251
+ static_attributes[attribute.name] = translated_value
252
+ end
253
+ value
254
+ end
255
+ end
256
+
257
+ # @api private
258
+ protected
259
+ def populates_from *request_types, &block
260
+ provider = provider(*request_types)
261
+ provider.find(&block)
262
+ provider.provides(*attributes.keys)
263
+ provider
264
+ end
265
+
266
+ # @api private
267
+ protected
268
+ def provider *request_types, &block
269
+ provider = AttributeProvider.new(self, request_types)
270
+ if block_given?
271
+ yield(provider)
272
+ end
273
+ attribute_providers << provider
274
+ provider
275
+ end
276
+
277
+ end
278
+
279
+ # @api private
280
+ class Attribute
281
+
282
+ def initialize name, options = {}
283
+ @name = name
284
+ @options = options
285
+ @request_types = []
286
+ end
287
+
288
+ attr_reader :name
289
+
290
+ attr_reader :request_types
291
+
292
+ def from
293
+ @from ||= (@options[:from] || name)
294
+ end
295
+
296
+ def set_as
297
+ @set_as ||= (@options[:set_as] || @options[:from] || name)
298
+ end
299
+
300
+ def mutable?
301
+ @options[:mutable] == true
302
+ end
303
+
304
+ def static?
305
+ @options[:static] == true
306
+ end
307
+
308
+ def translates_input &block
309
+ @input_translator = block
310
+ end
311
+
312
+ def translates_output options = {}, &block
313
+ @translates_nil = options[:nil]
314
+ @output_translator = block
315
+ end
316
+
317
+ def translate_input_value value
318
+ @input_translator ? @input_translator.call(value) : value
319
+ end
320
+
321
+ def translate_output_value value
322
+
323
+ # by default nil values are not translated
324
+ return nil if value.nil? and @translates_nil != true
325
+
326
+ case
327
+ when @options[:to_sym] then value.tr('-','_').downcase.to_sym
328
+ when @options[:timestamp] then Time.at(value.to_i)
329
+ when @output_translator then @output_translator.call(value)
330
+ else value
331
+ end
332
+
333
+ end
334
+
335
+ end
336
+
337
+ # @api private
338
+ class AttributeProvider
339
+
340
+ def initialize klass, request_types
341
+ @klass = klass
342
+ @id = klass.attribute_providers.length
343
+ @request_types = request_types
344
+ @provides = {}
345
+ end
346
+
347
+ attr_reader :request_types
348
+
349
+ def find &block
350
+ @klass.send(:define_method, finder_method, &block)
351
+ end
352
+
353
+ def finder_method
354
+ "_find_in_#{request_types.join('_or_')}_response_#{@id}"
355
+ end
356
+
357
+ # Indicates that all of the the named attributes can be retrieved
358
+ # from an appropriate response object.
359
+ #
360
+ # @overload provides(*attr_names, options = {})
361
+ # @param [Symbol] attr_names A list of attributes provided
362
+ # @param [Hash] options
363
+ # @option options [Boolean] :value_wrapped (false) If true, then
364
+ # the value returned by the response object will also receive
365
+ # the message :value before it is translated and returned.
366
+ # @option options [Symbol] :from Defaults to the method named
367
+ # by the attribute. This is useful when you have two providers
368
+ # for the same attribute but their response object name
369
+ # them differently.
370
+ def provides *attr_names
371
+ options = attr_names.last.is_a?(Hash) ? attr_names.pop : {}
372
+ attr_names.each do |attr_name|
373
+ attr = @klass.attributes[attr_name]
374
+ attr.request_types.push(*request_types)
375
+ @provides[attr_name] = options
376
+ end
377
+ end
378
+
379
+ def attributes_from_response resource, response
380
+ if response_object = resource.send(finder_method, response)
381
+ attributes_from_response_object(response_object)
382
+ else
383
+ nil
384
+ end
385
+ end
386
+
387
+ def attributes_from_response_object resp_obj
388
+
389
+ @provides.inject({}) do |attributes,(attr_name,options)|
390
+
391
+ attr = @klass.attributes[attr_name]
392
+
393
+ methods = [options[:from] || attr.from].flatten
394
+
395
+ v = resp_obj
396
+ methods.each do |method|
397
+ v = v.key?(method) ? v[method] : v[method.to_s]
398
+ break if v.nil?
399
+ end
400
+ v = v[:value] if v and options[:value_wrapped]
401
+ v = attr.translate_output_value(v)
402
+
403
+ attributes.merge(attr_name => v)
404
+
405
+ end
406
+
407
+ end
408
+
409
+ end
410
+ end
411
+ end
412
+ end
@@ -0,0 +1,39 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ # @api private
17
+ class ResourceCache
18
+
19
+ def initialize
20
+ @cache = {}
21
+ end
22
+
23
+ def store(key, attributes)
24
+ (@cache[key] ||= {}).merge!(attributes)
25
+ end
26
+
27
+ def cached?(key, attribute)
28
+ attributes = @cache[key] and attributes.has_key?(attribute)
29
+ end
30
+
31
+ def get(key, attribute)
32
+ raise "No cached value for attribute :#{attribute} of #{key}" unless
33
+ cached?(key, attribute)
34
+ @cache[key][attribute]
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,214 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ # # Response
17
+ #
18
+ # Each Service has a Client class. There is one method per service
19
+ # operation defined on the client. These methods all return a {Response}
20
+ # object.
21
+ #
22
+ # In addition to the response data, these responses provide metadata
23
+ # about the HTTP request made and the HTTP response received.
24
+ #
25
+ # ## Response Data
26
+ #
27
+ # You can access the response data for a client request using the {#data}
28
+ # method or the {#[]} method. Response data is a hash and {#[]} is
29
+ # a shortcut for accessing this hash.
30
+ #
31
+ # # make a request to describe one instance
32
+ # ec2 = MSS::EC2.new
33
+ # response = ec2.client.describe_instances(:instance_ids => ['i-12345678'])
34
+ #
35
+ # # find the instance in the response data (2 ways to get the data)
36
+ # instance = response[:reservation_set].first[:instance_set].first
37
+ # instance = response.data[:reservation_set].first[:instance_set].first
38
+ #
39
+ # instance[:status] #=> 'running'
40
+ #
41
+ # ## Response Metadata
42
+ #
43
+ # In addition to the response data, there is additional information
44
+ # available with the response, including:
45
+ #
46
+ # * {#request_type} - the name of the client request method
47
+ # * {#request_options} - the hash of options passed to the client method
48
+ # * {#http_request} - The HTTP request made
49
+ # * {#http_response} - the HTTP response received
50
+ #
51
+ # Given the example and response object from above:
52
+ #
53
+ # response.request_type #=> :describe_instances
54
+ # response.request_options #=> { :instance_ids => ['i-12345678'] }
55
+ # response.http_request #=> #<MSS::Core::Http::Request>
56
+ # response.http_response #=> #<MSS::Core::Http::Response>
57
+ #
58
+ class Response
59
+
60
+ include AsyncHandle
61
+
62
+ # @return [Hash] Returns the response data as a hash.
63
+ attr_accessor :data
64
+
65
+ # @api private
66
+ attr_accessor :config
67
+
68
+ # @return [Symbol] The name of the client request method that
69
+ # returned this response.
70
+ attr_accessor :request_type
71
+
72
+ # @return [String] The API version of the request/client.
73
+ attr_accessor :api_version
74
+
75
+ # @return [Hash] Returns the hash of options passed to the client
76
+ # request method that generated this response.
77
+ attr_accessor :request_options
78
+
79
+ # @return [Core::Http::Request]
80
+ attr_accessor :http_request
81
+
82
+ # @return [Core::Http::Response]
83
+ attr_accessor :http_response
84
+
85
+ # @return [Boolean] true if the response was generated from a
86
+ # another cached response.
87
+ attr_accessor :cached
88
+
89
+ alias_method :cached?, :cached
90
+
91
+ # @return [MSS::Error,nil] Returns nil unless the request failed.
92
+ # Normally this will be nil unless you are using the Asynchronous
93
+ # interface.
94
+ attr_accessor :error
95
+
96
+ # @return [Integer] Returns the number of times the request
97
+ # was retried.
98
+ attr_accessor :retry_count
99
+
100
+ # @return [Float] The total number of seconds taken to make the
101
+ # request and return the response.
102
+ attr_accessor :duration
103
+
104
+ # @param [Http::Request] http_request
105
+ # @param [Http::Response] http_response
106
+ def initialize http_request = nil, http_response = nil, &block
107
+ @http_request = http_request
108
+ @http_response = http_response
109
+ @request_builder = block
110
+ @data = {}
111
+ @retry_count = 0
112
+ @duration = 0
113
+ build_request if @request_builder && !http_request
114
+ end
115
+
116
+ # Provides access to the response data. This is a short-cut
117
+ # for calling `response.data[key]`.
118
+ #
119
+ # @param [Symbol,String] key
120
+ # @return [Hash,nil]
121
+ def [] key
122
+ data[key]
123
+ end
124
+
125
+ # @return [Boolean] Returns true if there is no response error.
126
+ def successful?
127
+ error.nil?
128
+ end
129
+
130
+ # @return [Boolean] Returns `true` if the http request failed due to
131
+ # a networking issue.
132
+ def network_error?
133
+ http_response.network_error?
134
+ end
135
+
136
+ # @return [String]
137
+ # @api private
138
+ def inspect
139
+ data.inspect
140
+ end
141
+
142
+ # @return [String]
143
+ # @api private
144
+ def cache_key
145
+ [
146
+ api_version,
147
+ http_request.access_key_id,
148
+ http_request.host,
149
+ request_type,
150
+ serialized_options
151
+ ].join(":")
152
+ end
153
+
154
+ # Rebuilds the HTTP request using the block passed to the initializer.
155
+ # This is primarily used by the client when a request must be retried
156
+ # (throttling, server errors, socket errors, etc).
157
+ # @api private
158
+ def rebuild_request
159
+ @http_request.body_stream.rewind if @http_request.body_stream
160
+ build_request
161
+ end
162
+
163
+ # @return [Boolean] Returns `false` if it is not safe to retry a
164
+ # request. This happens when the http request body is an IO
165
+ # object that can not be rewound and re-streamed.
166
+ def safe_to_retry?
167
+ @http_request.body_stream.nil? or
168
+ @http_request.body_stream.respond_to?(:rewind)
169
+ end
170
+
171
+ protected
172
+
173
+ def build_request
174
+ @http_request = @request_builder.call
175
+ end
176
+
177
+ # @note The prefered method to get as response data is to use {#[]}.
178
+ #
179
+ # This provides a backwards-compat layer to the old response objects
180
+ # where each response value had a method extended onto this object.
181
+ # Now all response data is accessible as a hash.
182
+ #
183
+ # @see #[]
184
+ # @see #data
185
+ #
186
+ def method_missing *args, &block
187
+ Core::Data.new(data).send(*args, &block)
188
+ end
189
+
190
+ def serialized_options
191
+ serialize_options_hash(request_options)
192
+ end
193
+
194
+ def serialize_options_hash(hash)
195
+ "(" + hash.keys.sort_by(&:to_s).map do |key|
196
+ "#{key}=#{serialize_options_value(hash[key])}"
197
+ end.join(" ") + ")"
198
+ end
199
+
200
+ def serialize_options_value(value)
201
+ case value
202
+ when Hash then serialize_options_hash(value)
203
+ when Array then serialize_options_array(value)
204
+ else value.inspect
205
+ end
206
+ end
207
+
208
+ def serialize_options_array array
209
+ "[" + array.map{|v| serialize_options_value(v) }.join(" ") + "]"
210
+ end
211
+
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ module Core
15
+
16
+ # @api private
17
+ class ResponseCache
18
+
19
+ attr_reader :cached_responses
20
+
21
+ attr_reader :resource_cache
22
+
23
+ def initialize
24
+ @cached_responses = []
25
+ @indexed_responses = {}
26
+ @resource_cache = ResourceCache.new
27
+ end
28
+
29
+ def add(resp)
30
+ cached_responses.unshift(resp)
31
+ @indexed_responses[resp.cache_key] = resp if
32
+ resp.respond_to?(:cache_key)
33
+ @resource_cache = ResourceCache.new
34
+ end
35
+
36
+ def select(*types, &block)
37
+ cached_responses.select do |resp|
38
+ types.map{|t| t.to_s }.include?(resp.request_type.to_s) and
39
+ (block.nil? || block.call(resp))
40
+ end
41
+ end
42
+
43
+ def cached(resp)
44
+ @indexed_responses[resp.cache_key]
45
+ end
46
+
47
+ end
48
+ end
49
+ end