em_aws 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/Gemfile.lock +54 -0
- data/README.md +33 -5
- data/em_aws.gemspec +1 -1
- data/lib/aws/core/http/em_http_handler.rb +43 -27
- data/lib/em_aws/version.rb +1 -1
- data/spec/em_http_handler_spec.rb +45 -43
- metadata +13 -12
data/.gitignore
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
em_aws (0.1.0)
|
5
|
+
aws-sdk
|
6
|
+
em-http-request
|
7
|
+
em-synchrony
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
addressable (2.2.7)
|
13
|
+
aws-sdk (1.3.9)
|
14
|
+
httparty (~> 0.7)
|
15
|
+
json (~> 1.4)
|
16
|
+
nokogiri (>= 1.4.4)
|
17
|
+
uuidtools (~> 2.1)
|
18
|
+
cookiejar (0.3.0)
|
19
|
+
diff-lcs (1.1.3)
|
20
|
+
em-http-request (1.0.2)
|
21
|
+
addressable (>= 2.2.3)
|
22
|
+
cookiejar
|
23
|
+
em-socksify
|
24
|
+
eventmachine (>= 1.0.0.beta.4)
|
25
|
+
http_parser.rb (>= 0.5.3)
|
26
|
+
em-socksify (0.2.0)
|
27
|
+
eventmachine (>= 1.0.0.beta.4)
|
28
|
+
em-synchrony (1.0.0)
|
29
|
+
eventmachine (>= 1.0.0.beta.1)
|
30
|
+
eventmachine (1.0.0.beta.4)
|
31
|
+
http_parser.rb (0.5.3)
|
32
|
+
httparty (0.8.1)
|
33
|
+
multi_json
|
34
|
+
multi_xml
|
35
|
+
json (1.6.6)
|
36
|
+
multi_json (1.2.0)
|
37
|
+
multi_xml (0.4.2)
|
38
|
+
nokogiri (1.5.2)
|
39
|
+
rspec (2.9.0)
|
40
|
+
rspec-core (~> 2.9.0)
|
41
|
+
rspec-expectations (~> 2.9.0)
|
42
|
+
rspec-mocks (~> 2.9.0)
|
43
|
+
rspec-core (2.9.0)
|
44
|
+
rspec-expectations (2.9.1)
|
45
|
+
diff-lcs (~> 1.1.3)
|
46
|
+
rspec-mocks (2.9.0)
|
47
|
+
uuidtools (2.1.2)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
em_aws!
|
54
|
+
rspec
|
data/README.md
CHANGED
@@ -6,27 +6,55 @@ Until approval (or if it is declined) I created this gem.
|
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
em_aws is available through [Rubygems](
|
9
|
+
em_aws is available through [Rubygems](https://rubygems.org/gems/em_aws) and can be installed via:
|
10
10
|
|
11
11
|
$ gem install em_aws
|
12
12
|
|
13
13
|
## Rails 3 setup (no rails 2 sorry)
|
14
14
|
Setup [AWS-SKD](https://github.com/amazonwebservices/aws-sdk-for-ruby/blob/master/README.rdoc) as you would normally.
|
15
15
|
|
16
|
-
Assuming you've already setup async-rails
|
16
|
+
Assuming you've already setup async-rails, add em_aws to you gemfile:
|
17
|
+
|
18
|
+
gem 'em_aws'
|
19
|
+
|
20
|
+
Then run:
|
21
|
+
|
22
|
+
bundle install
|
17
23
|
|
18
24
|
In your environments files add:
|
19
25
|
|
20
26
|
require 'aws-sdk'
|
21
27
|
require 'aws/core/http/em_http_handler'
|
22
28
|
AWS.config(
|
23
|
-
:http_handler => AWS::Http::EMHttpHandler.new
|
29
|
+
:http_handler => AWS::Http::EMHttpHandler.new(
|
30
|
+
:pool_size => 5,
|
31
|
+
:proxy => {:host => "http://myproxy.com", :port => 80}
|
32
|
+
))
|
24
33
|
|
25
34
|
Your done.
|
26
35
|
|
27
36
|
All requests to AWS will use EM-Synchrony's implementation of em-http-request for non-block HTTP request and fiber management.
|
28
37
|
|
29
|
-
|
38
|
+
## Connection Pools
|
39
|
+
v0.1+ implement connections EventMachine::Synchrony::ConnectionPool. The default pool_size is 5 but it can be
|
40
|
+
increased by in the AWS.config options. Connection pools were problematic for S3 calls that required the :path option for
|
41
|
+
em-http-request and would return AWS::S3::SignatureDoesNotMatch errors; so for now S3 calls with paths do not make use of the connection pools.
|
42
|
+
|
43
|
+
## Heroku Gotcha
|
44
|
+
When deploying to Heroku, if you get "NameError: uninitialized constant Syck::Syck", you need to vendorize em_aws
|
45
|
+
|
46
|
+
From your apps root directory run:
|
47
|
+
|
48
|
+
gem unpack em_aws --target vendor/gems
|
49
|
+
|
50
|
+
Update you gemfile:
|
51
|
+
|
52
|
+
gem 'em_aws', :path => "vendor/gems/em_aws-0.0.3"
|
53
|
+
|
54
|
+
Finally, run bundler and make sure you check-in your new Gemfile.lock.
|
55
|
+
I'm pretty sure the Syck error is do to an outdated version of rubygems and bundler on Heroku, but as of yet have not been able to reproduce it locally.
|
56
|
+
|
57
|
+
## References
|
30
58
|
|
31
59
|
[aws-sdk](https://github.com/amazonwebservices/aws-sdk-for-ruby)
|
32
60
|
|
@@ -45,4 +73,4 @@ All requests to AWS will use EM-Synchrony's implementation of em-http-request fo
|
|
45
73
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
46
74
|
|
47
75
|
## Thanks
|
48
|
-
Code based on HTTParty Hander in [
|
76
|
+
Code based on HTTParty Hander in [aws-sdk](https://github.com/amazonwebservices/aws-sdk-for-ruby/blob/master/README.rdoc)
|
data/em_aws.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.add_runtime_dependency "aws-sdk"
|
18
18
|
s.add_runtime_dependency "em-synchrony"
|
19
19
|
s.add_runtime_dependency "em-http-request"
|
20
|
-
s.add_development_dependency "rspec"
|
20
|
+
s.add_development_dependency "rspec"
|
21
21
|
|
22
22
|
s.files = `git ls-files`.split("\n")
|
23
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# http://docs.amazonwebservices.com/AWSRubySDK/latest/
|
2
|
-
|
3
2
|
require "em-synchrony"
|
4
3
|
require "em-synchrony/em-http"
|
5
|
-
|
4
|
+
require 'em-synchrony/thread'
|
6
5
|
module AWS
|
6
|
+
|
7
7
|
module Core
|
8
8
|
module Http
|
9
9
|
|
@@ -18,36 +18,46 @@ module AWS
|
|
18
18
|
# require 'aws/core/http/em_http_handler'
|
19
19
|
# AWS.config(
|
20
20
|
# :http_handler => AWS::Http::EMHttpHandler.new(
|
21
|
+
# :pool_size => 20,
|
21
22
|
# :proxy => {:host => "http://myproxy.com",:port => 80}
|
22
23
|
# )
|
23
24
|
# )
|
24
25
|
#
|
25
26
|
class EMHttpHandler
|
26
|
-
|
27
27
|
# @return [Hash] The default options to send to EM-Synchrony on each
|
28
28
|
# request.
|
29
29
|
attr_reader :default_request_options
|
30
|
-
|
30
|
+
@@pools = {}
|
31
|
+
|
32
|
+
def self.fetch_connection(url,pool_size)
|
33
|
+
@@pools[url] ||= EventMachine::Synchrony::ConnectionPool.new(size: pool_size) do
|
34
|
+
EM::HttpRequest.new(url)
|
35
|
+
end
|
36
|
+
@@pools[url]
|
37
|
+
end
|
38
|
+
|
31
39
|
# Constructs a new HTTP handler using EM-Synchrony.
|
32
40
|
#
|
33
|
-
# @param [Hash] options Default options to send to
|
41
|
+
# @param [Hash] options Default options to send to EM-Synchrony on
|
34
42
|
# each request. These options will be sent to +get+, +post+,
|
35
43
|
# +head+, +put+, or +delete+ when a request is made. Note
|
36
44
|
# that +:body+, +:head+, +:parser+, and +:ssl_ca_file+ are
|
37
45
|
# ignored. If you need to set the CA file, you should use the
|
38
46
|
# +:ssl_ca_file+ option to {AWS.config} or
|
39
47
|
# {AWS::Configuration} instead.
|
48
|
+
# Defaults pool_size to 5
|
40
49
|
def initialize options = {}
|
41
50
|
#puts "Using EM-Synchrony for AWS requests"
|
51
|
+
options[:pool_size] ||= 5
|
42
52
|
@default_request_options = options
|
43
53
|
end
|
44
54
|
|
45
55
|
def fetch_url(request)
|
46
56
|
url = nil
|
47
57
|
if request.use_ssl?
|
48
|
-
url = "https://#{request.host}:443
|
58
|
+
url = "https://#{request.host}:443"
|
49
59
|
else
|
50
|
-
url = "http://#{request.host}
|
60
|
+
url = "http://#{request.host}"
|
51
61
|
end
|
52
62
|
url
|
53
63
|
end
|
@@ -88,36 +98,43 @@ module AWS
|
|
88
98
|
merge(fetch_ssl(request))
|
89
99
|
end
|
90
100
|
|
101
|
+
# We get AWS::S3::SignatureDoesNotMatch when path is used to fetch an s3 object
|
102
|
+
# so for now we won't use the pool for requests where the path is more than just '/'
|
91
103
|
def fetch_response(url,method,opts={})
|
92
|
-
|
104
|
+
return EM::HttpRequest.new("#{url}#{opts[:path]}").send(method, opts) if (@default_request_options[:pool_size] == 0 || opts[:path].to_s.length > 1)
|
105
|
+
self.class.fetch_connection(url,@default_request_options[:pool_size]).send(method, opts)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Add thread safety.
|
109
|
+
def _fibered_mutex
|
110
|
+
@fibered_mutex ||= EM::Synchrony::Thread::Mutex.new
|
111
|
+
end
|
112
|
+
|
113
|
+
def handle(request,response)
|
93
114
|
if EM::reactor_running?
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
http.errback { puts "#{method} to AWS failed." }
|
115
|
+
_fibered_mutex.synchronize do
|
116
|
+
handle_it(request, response)
|
117
|
+
end
|
98
118
|
else
|
99
119
|
EM.synchrony do
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
http.errback { puts "#{method} to AWS failed." }
|
120
|
+
_fibered_mutex.synchronize do
|
121
|
+
handle_it(request, response)
|
122
|
+
end
|
104
123
|
EM.stop
|
105
|
-
end
|
124
|
+
end
|
106
125
|
end
|
107
|
-
new_response
|
108
126
|
end
|
109
|
-
|
110
|
-
def
|
111
|
-
|
127
|
+
|
128
|
+
def handle_it(request, response)
|
129
|
+
#puts "Using EM!!!!"
|
112
130
|
opts = default_request_options.merge({
|
113
|
-
:body => request.body
|
131
|
+
:body => request.body,
|
132
|
+
:path => request.uri,
|
133
|
+
|
114
134
|
}).merge(request_options(request))
|
115
|
-
|
116
135
|
url = fetch_url(request)
|
117
|
-
|
118
136
|
# get, post, put, delete, head
|
119
137
|
method = request.http_method.downcase
|
120
|
-
|
121
138
|
begin
|
122
139
|
http_response = fetch_response(url,method,opts)
|
123
140
|
rescue Timeout::Error, Errno::ETIMEDOUT => e
|
@@ -127,7 +144,7 @@ module AWS
|
|
127
144
|
response.status = http_response.response_header.status.to_i
|
128
145
|
response.headers = http_response.response_header.to_hash
|
129
146
|
end
|
130
|
-
end
|
147
|
+
end
|
131
148
|
end
|
132
149
|
end
|
133
150
|
end
|
@@ -138,5 +155,4 @@ module AWS
|
|
138
155
|
module Http
|
139
156
|
class EMHttpHandler < Core::Http::EMHttpHandler; end
|
140
157
|
end
|
141
|
-
|
142
158
|
end
|
data/lib/em_aws/version.rb
CHANGED
@@ -16,7 +16,7 @@ require 'spec_helper'
|
|
16
16
|
module AWS::Core
|
17
17
|
module Http
|
18
18
|
describe EMHttpHandler do
|
19
|
-
|
19
|
+
|
20
20
|
let(:handler) { EMHttpHandler.new(default_request_options) }
|
21
21
|
|
22
22
|
let(:default_request_options) { {} }
|
@@ -32,7 +32,6 @@ module AWS::Core
|
|
32
32
|
let(:em_http_options) do
|
33
33
|
options = nil
|
34
34
|
EMHttpHandler.should_receive(:fetch_response).with do |url, method,opts|
|
35
|
-
puts "here"
|
36
35
|
options = opts
|
37
36
|
double("http response",
|
38
37
|
:response => "<foo/>",
|
@@ -52,7 +51,12 @@ module AWS::Core
|
|
52
51
|
|
53
52
|
it 'should set the default request options' do
|
54
53
|
described_class.new(:foo => "BAR").default_request_options.
|
55
|
-
should == { :foo => "BAR" }
|
54
|
+
should == { :foo => "BAR", :pool_size => 5 }
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should not override supplied pool_size' do
|
58
|
+
described_class.new(:pool_size => 20).default_request_options.
|
59
|
+
should == { :pool_size => 20 }
|
56
60
|
end
|
57
61
|
|
58
62
|
end
|
@@ -101,61 +105,59 @@ module AWS::Core
|
|
101
105
|
|
102
106
|
end
|
103
107
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
handler.fetch_proxy(req)[:proxy][:port].should == 443
|
112
|
-
end
|
113
|
-
|
108
|
+
end
|
109
|
+
describe '#fetch_proxy' do
|
110
|
+
context ':proxy_uri' do
|
111
|
+
it 'passes proxy address and port from the request' do
|
112
|
+
req.proxy_uri = URI.parse('https://user:pass@proxy.com:443/path?query')
|
113
|
+
handler.fetch_proxy(req)[:proxy][:host].should == 'proxy.com'
|
114
|
+
handler.fetch_proxy(req)[:proxy][:port].should == 443
|
114
115
|
end
|
116
|
+
|
117
|
+
end
|
115
118
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
describe '#fetch_ssl' do
|
120
|
+
it 'prefers the request option when set' do
|
121
|
+
req.use_ssl = true
|
122
|
+
req.ssl_verify_peer = true
|
123
|
+
req.ssl_ca_file = "something"
|
124
|
+
handler.fetch_ssl(req)[:private_key_file].should == "something"
|
125
|
+
handler.fetch_ssl(req)[:cert_chain_file].should == "something"
|
126
|
+
end
|
124
127
|
|
125
|
-
|
126
|
-
|
127
|
-
context 'use_ssl? is true' do
|
128
|
+
context 'CA cert path' do
|
128
129
|
|
129
|
-
|
130
|
+
context 'use_ssl? is true' do
|
130
131
|
|
131
|
-
|
132
|
+
before(:each) { req.use_ssl = true }
|
132
133
|
|
133
|
-
|
134
|
-
req.ssl_verify_peer = true
|
135
|
-
req.ssl_ca_file = "foobar.txt"
|
136
|
-
end
|
134
|
+
context 'ssl_verify_peer? is true' do
|
137
135
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
it 'should use the ssl_ca_file attribute of the request' do
|
143
|
-
handler.fetch_ssl(req)[:cert_chain_file].should == "foobar.txt"
|
144
|
-
end
|
136
|
+
before(:each) do
|
137
|
+
req.ssl_verify_peer = true
|
138
|
+
req.ssl_ca_file = "foobar.txt"
|
145
139
|
end
|
146
140
|
|
147
|
-
it 'should
|
148
|
-
handler.fetch_ssl(req).
|
141
|
+
it 'should use the ssl_ca_file attribute of the request' do
|
142
|
+
handler.fetch_ssl(req)[:private_key_file].should == "foobar.txt"
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should use the ssl_ca_file attribute of the request' do
|
146
|
+
handler.fetch_ssl(req)[:cert_chain_file].should == "foobar.txt"
|
149
147
|
end
|
150
148
|
end
|
151
149
|
|
152
|
-
it 'should not set the ssl_ca_file option without
|
150
|
+
it 'should not set the ssl_ca_file option without ssl_verify_peer?' do
|
153
151
|
handler.fetch_ssl(req).should_not include(:private_key_file)
|
154
152
|
end
|
155
153
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
154
|
+
|
155
|
+
it 'should not set the ssl_ca_file option without use_ssl?' do
|
156
|
+
handler.fetch_ssl(req).should_not include(:private_key_file)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
159
161
|
end
|
160
162
|
end
|
161
163
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em_aws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-04-11 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|
16
|
-
requirement: &
|
16
|
+
requirement: &70247639340500 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70247639340500
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: em-synchrony
|
27
|
-
requirement: &
|
27
|
+
requirement: &70247639339960 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70247639339960
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: em-http-request
|
38
|
-
requirement: &
|
38
|
+
requirement: &70247639339420 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,18 +43,18 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70247639339420
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70247639338880 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70247639338880
|
58
58
|
description: Adds EM-Synchrony support to AWS-SDK gem
|
59
59
|
email:
|
60
60
|
- joshmckin@gmail.com
|
@@ -65,6 +65,7 @@ files:
|
|
65
65
|
- .gitignore
|
66
66
|
- .rspec
|
67
67
|
- Gemfile
|
68
|
+
- Gemfile.lock
|
68
69
|
- LICENSE.txt
|
69
70
|
- README.md
|
70
71
|
- Rakefile
|