class AwsSdb::Service
Public Class Methods
new(options={})
click to toggle source
# File lib/aws_sdb/service.rb, line 26 def initialize(options={}) @access_key_id = options[:access_key_id] || ENV['AMAZON_ACCESS_KEY_ID'] @secret_access_key = options[:secret_access_key] || ENV['AMAZON_SECRET_ACCESS_KEY'] @base_url = options[:url] || 'http://sdb.amazonaws.com' @logger = options[:logger] || Logger.new("aws_sdb.log") end
Public Instance Methods
create_domain(domain)
click to toggle source
# File lib/aws_sdb/service.rb, line 47 def create_domain(domain) domain.strip! if domain call(:post, { 'Action' => 'CreateDomain', 'DomainName'=> domain.to_s }) nil end
delete_attributes(domain, item)
click to toggle source
# File lib/aws_sdb/service.rb, line 146 def delete_attributes(domain, item) call( :delete, { 'Action' => 'DeleteAttributes', 'DomainName' => domain.to_s, 'ItemName' => item.to_s } ) nil end
delete_domain(domain)
click to toggle source
# File lib/aws_sdb/service.rb, line 53 def delete_domain(domain) call( :delete, { 'Action' => 'DeleteDomain', 'DomainName' => domain.to_s } ) nil end
get_attributes(domain, item, consistent_read = 'true')
click to toggle source
updated to support consitent read
# File lib/aws_sdb/service.rb, line 124 def get_attributes(domain, item, consistent_read = 'true') doc = call( :get, { 'Action' => 'GetAttributes', 'DomainName' => domain.to_s, 'ItemName' => item.to_s, 'ConsistentRead' => consistent_read } ) attributes = {} REXML::XPath.each(doc, "//Attribute") do |attr| unesc_key = REXML::XPath.first(attr, './Name/text()').to_s unesc_value = REXML::XPath.first(attr, './Value/text()').to_s #unescape key and value to return to normal key = CGI.unescape(unesc_key) value = CGI.unescape(unesc_value) ( attributes[key] ||= [] ) << value end attributes end
list_domains(max = nil, token = nil)
click to toggle source
# File lib/aws_sdb/service.rb, line 33 def list_domains(max = nil, token = nil) params = { 'Action' => 'ListDomains' } params['NextToken'] = token unless token.nil? || token.empty? params['MaxNumberOfDomains'] = max.to_s unless max.nil? || max.to_i == 0 doc = call(:get, params) results = [] REXML::XPath.each(doc, '//DomainName/text()') do |domain| results << domain.to_s end return results, REXML::XPath.first(doc, '//NextToken/text()').to_s end
put_attributes(domain, item, attributes, replace = true)
click to toggle source
# File lib/aws_sdb/service.rb, line 103 def put_attributes(domain, item, attributes, replace = true) params = { 'Action' => 'PutAttributes', 'DomainName' => domain.to_s, 'ItemName' => item.to_s } count = 0 #escaping key and value so signature computes correctly attributes.each do | key, values | ( []<<values ).flatten.each do |value| params["Attribute.#{count}.Name"] = CGI.escape(key.to_s) params["Attribute.#{count}.Value"] = CGI.escape(value.to_s) params["Attribute.#{count}.Replace"] = replace count += 1 end end call(:put, params) nil end
select(query, max = nil, token = nil, consistent_read = 'true')
click to toggle source
# File lib/aws_sdb/service.rb, line 61 def select(query, max = nil, token = nil, consistent_read = 'true') query params = { 'Action' => 'Select', 'SelectExpression' => query, 'ConsistentRead' => consistent_read } params['NextToken'] = token unless token.nil? || token.empty? params['MaxNumberOfItems'] = max.to_s unless max.nil? || max.to_i == 0 @logger.debug { "SELECT EXPRESSION BEFORE CALL: #{query.inspect}" } if @logger.debug? doc = call(:get, params) items = {} attributes = {} #build the result hash REXML::XPath.each(doc, '//Item') do |item_doc| item_name = item_doc.elements["Name"].text item_doc.each do |attrib_doc| att_name = attrib_doc.elements["Name"] att_value = attrib_doc.elements["Value"] next unless (att_name && att_value) attrib_name = CGI.unescape(att_name.text) attrib_value = CGI.unescape(att_value.text) add_value(attributes, attrib_name, attrib_value) end items[item_name] = attributes #reset attributes so we don't clobber next item attributes = {} items end results = items return results, REXML::XPath.first(doc, '//NextToken/text()').to_s end
Protected Instance Methods
build_actual_query_string(q_params)
click to toggle source
# File lib/aws_sdb/service.rb, line 164 def build_actual_query_string(q_params) q_params.sort.collect { |k,v| [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')}.join('&') end
build_canonical_query_string(q_params)
click to toggle source
# File lib/aws_sdb/service.rb, line 160 def build_canonical_query_string(q_params) q_params.sort.collect { |k,v| [CGI.escape(k.to_s), CGI.escape(v.to_s)].join('=')}.join('&') end
call(method, params)
click to toggle source
# File lib/aws_sdb/service.rb, line 168 def call(method, params) #updated to support signtature version 2 params.merge!( { 'Version' => '2009-04-15', 'SignatureMethod' => 'HmacSHA256', #'SignatureMethod' => 'HmacSHA1', 'SignatureVersion' => '2', 'AWSAccessKeyId' => @access_key_id, 'Timestamp' => Time.now.gmtime.iso8601 } ) @logger.debug { "CALL: #{method} with #{params.inspect}" } if @logger.debug? canonical_querystring = build_canonical_query_string(params) @logger.debug { "CANONICAL: #{canonical_querystring.inspect}" } if @logger.debug? string_to_sign= "GET\n#{URI.parse(@base_url).host}\n/\n#{canonical_querystring}" #sha256 digest = OpenSSL::Digest::Digest.new('sha256') signature = Base64.encode64(OpenSSL::HMAC.digest(digest, @secret_access_key, string_to_sign)).chomp #sha1 #digest = OpenSSL::Digest::Digest.new('sha256') #signature = Base64.encode64(OpenSSL::HMAC.digest(digest, @secret_access_key, string_to_sign)).chomp params['Signature'] = signature querystring = build_actual_query_string(params) @logger.debug { "ACTUALQUERY: #{querystring.inspect}" } if @logger.debug? url = "#{@base_url}?#{querystring}" uri = URI.parse(url) resp = request(url) resp_body = resp.body @logger.debug { "RESP: #{resp_body.inspect}" } if @logger.debug? doc = REXML::Document.new(resp_body) @logger.debug { "DECODED DOC:" } if @logger.debug? error = doc.get_elements('*/Errors/Error')[0] raise( Module.class_eval( "AwsSdb::#{error.get_elements('Code')[0].text}Error" ).new( error.get_elements('Message')[0].text, doc.get_elements('*/RequestID')[0].text ) ) unless error.nil? doc end
request(url, retry_data={})
click to toggle source
request with retries
# File lib/aws_sdb/service.rb, line 225 def request(url, retry_data={}) resp = CurbFu.get(url) if resp.nil? || resp.status == 503 resp = retry_req(url, retry_data) end raise "No response!!" unless resp raise "No Body in Response" unless resp.body resp end
Private Instance Methods
add_value(attributes, attrib_name, attrib_value)
click to toggle source
# File lib/aws_sdb/service.rb, line 258 def add_value(attributes, attrib_name, attrib_value) if attributes[attrib_name] attributes[attrib_name] << attrib_value else attributes[attrib_name] = [attrib_value] end attributes end
retry_req(url, retry_data)
click to toggle source
# File lib/aws_sdb/service.rb, line 237 def retry_req(url, retry_data) resp = :retry #retry parameters max_retries = 10||retry_data[:max_retries] init_wait = 0.2||retry_data[:init_wait] wait_increase = 0.3||retry_data[:wait_increase] retry_data[:wait] = init_wait||retry_data[:wait] #wait a tiny bit before the first retry and reset retry data #then retry 1.upto(max_retries) do |retry_att| sleep retry_data[:wait] #puts "RETRY: #{retry_att}, WAIT: #{retry_data[:wait]}" resp = request(url, retry_data) break if resp && resp.status && resp.status != 503 && resp.body retry_data[:wait] += wait_increase retry_data[:wait_increase] = wait_increase * retry_att #request back off end resp end