class AWS::Core::Client
@private
Base class for all of the Amazon AWS service clients.
def self.add_client_request_method method_name, options = {}, &block
def self.add_client_request_method method_name, options = {}, &block method = ClientRequestMethodBuilder.new(self, method_name, &block) if xml_grammar = options[:xml_grammar] method.process_response do |resp| xml_grammar.parse(resp.http_response.body, :context => resp) super(resp) end method.simulate_response do |resp| xml_grammar.simulate(resp) super(resp) end end module_eval <<-END def #{method_name}(*args, &block) options = args.first ? args.first : {} client_request(#{method_name.inspect}, options, &block) end END end
def self.configure_client
def self.configure_client module_eval('module Options; end') module_eval('module XML; end') end
def async_request_with_retries response, http_request, retry_delays = nil
def async_request_with_retries response, http_request, retry_delays = nil response.http_response = Http::Response.new handle = Object.new handle.extend AsyncHandle handle.on_complete do |status| case status when :failure response.error = StandardError.new("failed to contact the service") response.signal_failure when :success populate_error(response) retry_delays ||= sleep_durations(response) if should_retry?(response) and !retry_delays.empty? response.rebuild_request @http_handler.sleep_with_callback(retry_delays.shift) do async_request_with_retries(response, response.http_request, retry_delays) end else response.error ? response.signal_failure : response.signal_success end end end @http_handler.handle_async(http_request, response.http_response, handle) end
def build_request(name, options, &block)
def build_request(name, options, &block) # we dont want to pass the async option to the configure block opts = options.dup opts.delete(:async) http_request = new_request # configure the http request http_request.host = endpoint http_request.proxy_uri = config.proxy_uri http_request.use_ssl = config.use_ssl? http_request.ssl_verify_peer = config.ssl_verify_peer? http_request.ssl_ca_file = config.ssl_ca_file send("configure_#{name}_request", http_request, opts, &block) http_request.headers["user-agent"] = user_agent_string http_request.add_authorization!(signer) http_request end
def client_request name, options, &block
def client_request name, options, &block return_or_raise(options) do log_client_request(name, options) do if config.stub_requests? response = stub_for(name) response.http_request = build_request(name, options, &block) response.request_options = options response else client = self response = new_response { client.send(:build_request, name, options, &block) } response.request_type = name response.request_options = options if self.class::CACHEABLE_REQUESTS.include?(name) and cache = AWS.response_cache and cached_response = cache.cached(response) cached_response.cached = true cached_response else # process the http request options[:async] ? make_async_request(response) : make_sync_request(response) # process the http response response.on_success do send("process_#{name}_response", response) if cache = AWS.response_cache cache.add(response) end end response end end end end end
def endpoint
-
(String)
- the configured endpoint for this client.
def endpoint config.send(:"#{self.class.service_ruby_name}_endpoint") end
def initialize options = {}
HTTP requests that this client constructs.
is BuiltinHttpHandler. This method is used to perform the
handle(request, response)
method; an example* +:http_handler+ -- Any object that implements a
== Optional
Secret Access Key directly to the client.
these options to provide the AWS Access Key ID and AWS
* +:access_key_id+ and +:secret_access_key+ -- You can use
different process).
example by moving the signature computation into a
more tightly control access to your secret access key (for
AWS::Core::DefaultSigner. This option is useful if you want to
for a given string). An example implementation is
sign(string_to_sign)
(to return a signature(to return the AWS Access Key ID) and to
* +:signer+ -- An object that responds to +access_key_id+
There are two options:
To create a client you must provide access to AWS credentials.
== Required Options
Creates a new low-level client.
def initialize options = {} if options[:endpoint] options[:"#{self.class.service_ruby_name}_endpoint"] = options.delete(:endpoint) end options_without_config = options.dup @config = options_without_config.delete(:config) @config ||= AWS.config @config = @config.with(options_without_config) @signer = @config.signer @http_handler = @config.http_handler @stubs = {} end
def make_async_request response
def make_async_request response pauses = async_request_with_retries(response, response.http_request) response end
def make_sync_request response
def make_sync_request response retry_server_errors do response.http_response = http_response = Http::Response.new @http_handler.handle(response.http_request, http_response) populate_error(response) response.signal_success unless response.error response end end
def new_request
def new_request req = self.class::REQUEST_CLASS.new req.http_method = 'POST' req.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8' req.add_param 'Timestamp', Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ') req.add_param 'Version', self.class::API_VERSION req end
def new_response(*args, &block)
def new_response(*args, &block) Response.new(*args, &block) end
def new_stub_for method_name
- Private: -
def new_stub_for method_name response = Response.new(Http::Request.new, Http::Response.new) response.request_type = method_name response.request_options = {} send("simulate_#{method_name}_response", response) response.signal_success response end
def populate_error response
def populate_error response # clear out a previous error response.error = nil status = response.http_response.status code = nil code = xml_error_grammar.parse(response.http_response.body).code if xml_error_response?(response) case when response.timeout? response.error = Timeout::Error.new when code response.error = service_module::Errors.error_class(code).new(response.http_request, response.http_response) when status >= 500 response.error = Errors::ServerError.new(response.http_request, response.http_response) when status >= 300 response.error = Errors::ClientError.new(response.http_request, response.http_response) end end
def retry_server_errors &block
def retry_server_errors &block response = yield sleeps = sleep_durations(response) while should_retry?(response) break if sleeps.empty? Kernel.sleep(sleeps.shift) # rebuild the request to get a fresh signature response.rebuild_request response = yield end response end
def return_or_raise options, &block
def return_or_raise options, &block response = yield unless options[:async] raise response.error if response.error end response end
def scaling_factor response
def scaling_factor response response.throttled? ? (0.5 + Kernel.rand * 0.1) : 0.3 end
def service_module
def service_module AWS.const_get(self.class.to_s[/(\w+)::Client/, 1]) end
def should_retry? response
def should_retry? response response.timeout? or response.throttled? or response.error.kind_of?(Errors::ServerError) end
def sleep_durations response
def sleep_durations response factor = scaling_factor(response) Array.new(config.max_retries) {|n| (2 ** n) * factor } end
def stub_for method_name
- Private: -
Other tags:
- See: new_stub_for -
def stub_for method_name @stubs[method_name] ||= new_stub_for(method_name) end
def user_agent_string
def user_agent_string engine = (RUBY_ENGINE rescue nil or "ruby") user_agent = "%s aws-sdk-ruby/#{VERSION} %s/%s %s" % [config.user_agent_prefix, engine, RUBY_VERSION, RUBY_PLATFORM] user_agent.strip! if AWS.memoizing? user_agent << " memoizing" end user_agent end
def with_config config
-
(Core::Client)
- Returns a new client object with the given
Parameters:
-
The
(Configuration
) -- configuration object to use.
def with_config config self.class.new(:config => config) end
def with_http_handler(handler = nil, &blk)
-
(Core::Client)
- Returns a new instance of the client class with
Parameters:
-
handler
(nil
) -- A new http handler. Leave blank and pass a
def with_http_handler(handler = nil, &blk) handler ||= Http::Handler.new(@http_handler, &blk) with_options(:http_handler => handler) end
def with_options options
- See: AWS.config - detailed list of accepted options.
Parameters:
-
options
(Hash
) --
def with_options options with_config(config.with(options)) end
def xml_error_grammar
def xml_error_grammar if service_module::const_defined?(:Errors) and service_module::Errors::const_defined?(:BASE_ERROR_GRAMMAR) service_module::Errors::BASE_ERROR_GRAMMAR else XmlGrammar end end
def xml_error_response? response
def xml_error_response? response response.http_response.status >= 300 and response.http_response.body and xml_error_grammar.parse(response.http_response.body).respond_to?(:code) end