Class: Amazon::SDB::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/amazon_sdb/base.rb

Overview

The Amazon::SDS::Base class is the top-level interface class for your SDS interactions. It allows you to set global configuration settings, to manage Domain objects. If you are working within a particular domain you can also just use the domain initializer directly for that domain.

Direct Known Subclasses

Domain

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(aws_access_key, aws_secret_key) ⇒ Base

The base is initialized with 2 parameters from your Amazon Web Services account:

  • aws_access_key - Your AWS Access Key

  • aws_secret_key - Your AWS Secret Key



15
16
17
18
# File 'lib/amazon_sdb/base.rb', line 15

def initialize(aws_access_key, aws_secret_key)
  @access_key = aws_access_key
  @secret_key = aws_secret_key
end

Class Method Details

.float_precisionObject



35
36
37
# File 'lib/amazon_sdb/base.rb', line 35

def self.float_precision
  return @@float_precision
end

.float_precision=(num) ⇒ Object



39
40
41
# File 'lib/amazon_sdb/base.rb', line 39

def self.float_precision=(num)
  return @@float_precision
end

.hmac(key, msg) ⇒ Object



106
107
108
# File 'lib/amazon_sdb/base.rb', line 106

def self.hmac(key, msg) 
  Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), key, msg))
end

.number_paddingObject

Since all SDS supports only lexical comparisons, it’s necessary to pad numbers with extra digits when saving them to SDS. Under lexical matching, 23 > 123. But if we pad it sufficiently 000000023 < 000000123. By default, this is set to the ungodly large value of 32 digits, but you can adjust it lower if this is too much. On reading from SDS, such numbers are auto-coerced back, so it’s probably not necessary to change.



25
26
27
# File 'lib/amazon_sdb/base.rb', line 25

def self.number_padding
  return @@number_padding
end

.number_padding=(num) ⇒ Object

Change the number padding



31
32
33
# File 'lib/amazon_sdb/base.rb', line 31

def self.number_padding=(num)
  @@number_padding = num
end

.sign(key, query_options) ⇒ Object



144
145
146
147
# File 'lib/amazon_sdb/base.rb', line 144

def self.sign(key, query_options)
  option_array = query_options.to_a.map {|pair| [pair[0].to_s, pair[1].to_s]}.sort {|a, b| a[0].downcase <=> b[0].downcase }
  return hmac(key, option_array.map {|pair| pair[0]+pair[1]}.join('')).chop
end

.uriencode(str) ⇒ Object



140
141
142
# File 'lib/amazon_sdb/base.rb', line 140

def self.uriencode(str)
  CGI.escape str.to_s
end

Instance Method Details

#cgi_encode(options) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# File 'lib/amazon_sdb/base.rb', line 110

def cgi_encode(options) 
  options.map do |k, v| 
    case v
    when Array
      v.map{|i| Base.uriencode(k)+'='+Base.uriencode(i)}.join('&')
    else
      Base.uriencode(k)+'='+Base.uriencode(v)
    end
  end.join('&')
end

#create_domain(name) ⇒ Object



90
91
92
93
94
# File 'lib/amazon_sdb/base.rb', line 90

def create_domain(name)
  sdb_query({:Action => 'CreateDomain', 'DomainName' => name}) do |h|
    domain(name)
  end
end

#delete_domain!(name) ⇒ Object

Deletes a domain. This operation is currently not supported by SDS.



98
99
100
# File 'lib/amazon_sdb/base.rb', line 98

def delete_domain!(name)
  sdb_query({:Action => 'DeleteDomain', 'DomainName' => name})
end

#domain(name) ⇒ Object

Returns a domain object for SDS. Assumes the domain already exists, so errors might occur if you didn’t create it.



71
72
73
# File 'lib/amazon_sdb/base.rb', line 71

def domain(name)
  Domain.new(@access_key, @secret_key, name)
end

#domainsObject

Retrieves a list of domains in your SDS database. Each entry is a Domain object.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/amazon_sdb/base.rb', line 45

def domains
  domains = []
  nextToken = nil
  base_options = {:Action => 'ListDomains'}
  continue = true
  
  while continue
    options = base_options.dup
    options[:NextToken] = nextToken unless nextToken.nil?
    
    sdb_query(options) do |h|
      h.search('//DomainName').each {|e| domains << Domain.new(@access_key, @secret_key, e.innerText)}
      mt = h.at('//NextToken')
      if mt
        nextToken = mt.innerText
      else
        continue = false
      end
    end
  end
  
  domains
end

#raise_errors(hpricot) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/amazon_sdb/base.rb', line 75

def raise_errors(hpricot)
  errnode = hpricot.at('//Errors/Error')
  return unless errnode
  
  msg = errnode.at('Message').innerText
  case errnode.at('Code').innerText
  when 'InvalidParameterValue'
    raise InvalidParameterError, msg
  when 'NumberDomainsExceeded'
    raise DomainLimitError, msg
  else
    raise UnknownError, msg
  end
end

#sdb_query(options = {}) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/amazon_sdb/base.rb', line 121

def sdb_query(options = {})
  options.merge!({'AWSAccessKeyId' => @access_key,
    'SignatureVersion'             => SIGNATURE_VERSION,
    'Timestamp'                    => timestamp,
    'Version'                      => API_VERSION })
  options['Signature'] = Base.sign(@secret_key, options)

  # send to S3
  url = BASE_PATH + '?' + cgi_encode(options)

  # puts "Requesting #{url}" #if $DEBUG
  open(url) do |f|
    h = Hpricot.XML(f)

    raise_errors h
    yield h if block_given?
  end
end

#timestampObject



102
103
104
# File 'lib/amazon_sdb/base.rb', line 102

def timestamp
  Time.now.iso8601
end