dynamodb-streams-client 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e95440be2067736e0cd514c71a361dd7094a3ad6
4
+ data.tar.gz: ffdfa5b4af5bd7bc2a431b866bc619cc4c8e9de3
5
+ SHA512:
6
+ metadata.gz: 3a7a38e41cd76c98d9af8cd2407438f226642d71ca30e293ca6fc0565c11abd726e92a6230dc6c3083c29137225ed78751d0902aecd7c21678fb81315962080e
7
+ data.tar.gz: ecc5b28c94a364f96be2757cbde5d893b1d71237941c7c6c0c6ff8ffc3eb93fdf8d3ef251bcf9af3c619d44361f99fdb353270088b98b8efcd6af309f32fe45a
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ test.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dynamodb-streams-client.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Genki Sugawara
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Dynamodb::Streams::Client
2
+
3
+ [DynamoDB Streams](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html) client.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'dynamodb-streams-client'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dynamodb-streams-client
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ client = DynamoDB::Streams::Client.new(
25
+ access_key_id: 'YOUR_ACCESS_KEY_ID',
26
+ secret_access_key: 'YOUR_SECRET_ACCESS_KEY',
27
+ endpoint: '...')
28
+
29
+ #client.debug = true
30
+
31
+ pp client.query('ListStreams')
32
+ #=> {"StreamIds"=>
33
+ # ["...",
34
+ # "...",
35
+ # "..."]}
36
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dynamodb/streams/client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'dynamodb-streams-client'
8
+ spec.version = DynamoDB::Streams::Client::VERSION
9
+ spec.authors = ['Genki Sugawara']
10
+ spec.email = ['sgwr_dts@yahoo.co.jp']
11
+ spec.summary = %q{DynamoDB Streams client.}
12
+ spec.description = %q{DynamoDB Streams client.}
13
+ spec.homepage = 'https://github.com/winebarrel/dynamodb-streams-client'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler'
22
+ spec.add_development_dependency 'rake'
23
+ end
@@ -0,0 +1,226 @@
1
+ require 'json'
2
+ require 'openssl'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'time'
6
+ require 'stringio'
7
+ require 'zlib'
8
+ require 'uri'
9
+
10
+ require 'dynamodb/streams/client/version'
11
+
12
+ class DynamoDB::Streams::Client
13
+ class Error < StandardError
14
+ attr_reader :data
15
+
16
+ def initialize(error_message, data = {})
17
+ super(error_message)
18
+ @data = data
19
+ end
20
+ end
21
+
22
+ SERVICE_NAME = 'dynamodb'
23
+ API_VERSION = '2012-08-10'
24
+ USER_AGENT = "dynamodb-streams-client/#{DynamoDB::Streams::Client::VERSION}"
25
+
26
+ DEFAULT_TIMEOUT = 60
27
+
28
+ attr_accessor :timeout
29
+ attr_accessor :retry_num
30
+ attr_accessor :retry_intvl
31
+ attr_accessor :debug
32
+
33
+ def initialize(options)
34
+ @accessKeyId = options.fetch(:access_key_id)
35
+ @secretAccessKey = options.fetch(:secret_access_key)
36
+ @endpoint = URI.parse(options.fetch(:endpoint))
37
+ @region = options[:region] || /([^.]+)\.amazonaws\.com\z/.match(@endpoint.host)[1]
38
+ @timeout = DEFAULT_TIMEOUT
39
+ @debug = false
40
+ @retry_num = 3
41
+ @retry_intvl = 10
42
+ end
43
+
44
+ def query(action, hash = {})
45
+ retry_query do
46
+ query0(action, hash)
47
+ end
48
+ end
49
+
50
+ def query0(action, hash)
51
+ req_body = JSON.dump(hash)
52
+ date = Time.now.getutc
53
+
54
+ headers = {
55
+ 'Content-Type' => 'application/x-amz-json-1.0',
56
+ 'X-Amz-Target' => "DynamoDBStreams_#{API_VERSION.gsub('-', '')}.#{action}",
57
+ 'Content-Length' => req_body.length.to_s,
58
+ 'User-Agent' => USER_AGENT,
59
+ 'Host' => @endpoint.host,
60
+ 'X-Amz-Date' => iso8601(date),
61
+ 'X-Amz-Content-Sha256' => hexhash(req_body),
62
+ 'Accept' => '*/*',
63
+ 'Accept-Encoding' => 'gzip',
64
+ }
65
+
66
+ headers['Authorization'] = authorization(date, headers, req_body)
67
+
68
+ Net::HTTP.version_1_2
69
+ http = Net::HTTP.new(@endpoint.host, @endpoint.port)
70
+
71
+ if @endpoint.scheme == 'https'
72
+ http.use_ssl = true
73
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
74
+ end
75
+
76
+ if @debug
77
+ http.set_debug_output($stderr)
78
+ end
79
+
80
+ http.open_timeout = @timeout
81
+ http.read_timeout = @timeout
82
+
83
+ res_code = nil
84
+ res_msg = nil
85
+
86
+ res_body = http.start do |w|
87
+ req = Net::HTTP::Post.new('/', headers)
88
+ req.body = req_body
89
+ res = w.request(req)
90
+
91
+ res_code = res.code.to_i
92
+ res_msg = res.message
93
+
94
+ if res['Content-Encoding'] == 'gzip'
95
+ StringIO.open(res.body, 'rb') do |f|
96
+ Zlib::GzipReader.wrap(f).read
97
+ end
98
+ else
99
+ res.body
100
+ end
101
+ end
102
+
103
+ res_data = JSON.parse(res_body)
104
+ __type = res_data['__type']
105
+
106
+ if res_code != 200 or __type
107
+ errmsg = if __type
108
+ if @debug
109
+ "#{__type}: #{res_data['message'] || res_data['Message']}"
110
+ else
111
+ "#{res_data['message'] || res_data['Message']}"
112
+ end
113
+ else
114
+ "#{res_code} #{res_msg}"
115
+ end
116
+
117
+ raise DynamoDB::Streams::Client::Error.new(errmsg, res_data)
118
+ end
119
+
120
+ res_data
121
+ end
122
+
123
+ private
124
+
125
+ def authorization(date, headers, body)
126
+ headers = headers.sort_by {|name, value| name }
127
+
128
+ # Task 1: Create a Canonical Request For Signature Version 4
129
+ # http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
130
+
131
+ canonicalHeaders = headers.map {|name, value|
132
+ name.downcase + ':' + value
133
+ }.join("\n") + "\n"
134
+
135
+ signedHeaders = headers.map {|name, value| name.downcase }.join(';')
136
+
137
+ canonicalRequest = [
138
+ 'POST', # HTTPRequestMethod
139
+ '/', # CanonicalURI
140
+ '', # CanonicalQueryString
141
+ canonicalHeaders,
142
+ signedHeaders,
143
+ hexhash(body),
144
+ ].join("\n")
145
+
146
+ # Task 2: Create a String to Sign for Signature Version 4
147
+ # http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
148
+
149
+ credentialScope = [
150
+ date.strftime('%Y%m%d'),
151
+ @region,
152
+ SERVICE_NAME,
153
+ 'aws4_request',
154
+ ].join('/')
155
+
156
+ stringToSign = [
157
+ 'AWS4-HMAC-SHA256', # Algorithm
158
+ iso8601(date), # RequestDate
159
+ credentialScope,
160
+ hexhash(canonicalRequest),
161
+ ].join("\n")
162
+
163
+ # Task 3: Calculate the AWS Signature Version 4
164
+ # http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
165
+
166
+ kDate = hmac('AWS4' + @secretAccessKey, date.strftime('%Y%m%d'))
167
+ kRegion = hmac(kDate, @region)
168
+ kService = hmac(kRegion, SERVICE_NAME)
169
+ kSigning = hmac(kService, 'aws4_request')
170
+ signature = hexhmac(kSigning, stringToSign)
171
+
172
+ 'AWS4-HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s' % [
173
+ @accessKeyId,
174
+ credentialScope,
175
+ signedHeaders,
176
+ signature,
177
+ ]
178
+ end
179
+
180
+ def iso8601(utc)
181
+ utc.strftime('%Y%m%dT%H%M%SZ')
182
+ end
183
+
184
+ def hexhash(data)
185
+ OpenSSL::Digest::SHA256.new.hexdigest(data)
186
+ end
187
+
188
+ def hmac(key, data)
189
+ OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, key, data)
190
+ end
191
+
192
+ def hexhmac(key, data)
193
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, key, data)
194
+ end
195
+
196
+ def retry_query
197
+ retval = nil
198
+
199
+ (@retry_num + 1).times do |i|
200
+ begin
201
+ retval = yield
202
+ break
203
+ rescue Errno::ETIMEDOUT => e
204
+ raise e if i >= @retry_num
205
+ rescue DynamoDB::Streams::Client::Error => e
206
+ if [/\bServiceUnavailable\b/i, /\bexceeded\b/i].any? {|i| i =~ e.message }
207
+ raise e if i >= @retry_num
208
+ else
209
+ raise e
210
+ end
211
+ rescue Timeout::Error => e
212
+ raise e if i >= @retry_num
213
+ end
214
+
215
+ wait_sec = @retry_intvl * (i + 1)
216
+
217
+ if @debug
218
+ $stderr.puts("Retry... (wait %d seconds)" % wait_sec)
219
+ end
220
+
221
+ sleep wait_sec
222
+ end
223
+
224
+ return retval
225
+ end
226
+ end
@@ -0,0 +1,7 @@
1
+ module DynamoDB
2
+ module Streams
3
+ class Client
4
+ VERSION = '0.0.1'
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dynamodb-streams-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Genki Sugawara
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: DynamoDB Streams client.
42
+ email:
43
+ - sgwr_dts@yahoo.co.jp
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - dynamodb-streams-client.gemspec
54
+ - lib/dynamodb/streams/client.rb
55
+ - lib/dynamodb/streams/client/version.rb
56
+ homepage: https://github.com/winebarrel/dynamodb-streams-client
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.0.14
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: DynamoDB Streams client.
80
+ test_files: []