em-xmlrpc-client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ vendor/bundle
6
+ doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in em-xmlrpc-client.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ em-xmlrpc-client (1.0.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ addressable (2.2.6)
10
+ crack (0.1.8)
11
+ em-http-request (0.3.0)
12
+ addressable (>= 2.0.0)
13
+ escape_utils
14
+ eventmachine (>= 0.12.9)
15
+ escape_utils (0.2.3)
16
+ eventmachine (0.12.10)
17
+ rr (1.0.3)
18
+ webmock (1.6.4)
19
+ addressable (~> 2.2, > 2.2.5)
20
+ crack (>= 0.1.7)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ em-http-request
27
+ em-xmlrpc-client!
28
+ eventmachine
29
+ rr
30
+ webmock
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Christopher J. Bottaro
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,31 @@
1
+ = em-xmlrpc-client
2
+
3
+ This gem monkey patches Ruby's built in XMLRPC::Client to be EventMachine + Fiber aware. If you are not using EventMachine (or the reactor isn't running), then it will fallback to using XMLRPC::Client's default implemenation (using Net::HTTP).
4
+
5
+ == Example
6
+
7
+ require "eventmachine"
8
+ require "em-xmlrpc-client"
9
+
10
+ EM.run do
11
+ Fiber.new do
12
+ client = XMLRPC::Client.new2("http://blah.com/api")
13
+ result = client.call("someMethod", "arg1", 123) # Uses em-http-request.
14
+ end.resume
15
+ end
16
+
17
+
18
+ client = XMLRPC::Client.new2("http://blah.com/api")
19
+ result = client.call("someMethod", "arg1", 123) # Uses Net::HTTP like normal.
20
+
21
+ == Dependencies
22
+
23
+ {em-http-request}[https://github.com/igrigorik/em-http-request] is required if you want to use the EventMachine + Fiber aware implementation.
24
+
25
+ == Author
26
+
27
+ Christopher J. Bottaro
28
+
29
+ {\https://github.com/cjbottaro}[https://github.com/cjbottaro]
30
+
31
+ @cjbottaro
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "em-xmlrpc-client/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "em-xmlrpc-client"
7
+ s.version = Em::Xmlrpc::Client::VERSION
8
+ s.authors = ["Christopher J. Bottaro"]
9
+ s.email = ["cjbottaro@alumni.cs.utexas.edu"]
10
+ s.homepage = ""
11
+ s.summary = %q{Evented and fibered XMLRPC Client}
12
+ s.description = %q{Monkey patches Ruby's standard XMLRPC Client to use EventMachine and fibers}
13
+
14
+ s.rubyforge_project = "em-xmlrpc-client"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "eventmachine"
23
+ s.add_development_dependency "em-http-request"
24
+ s.add_development_dependency "webmock"
25
+ s.add_development_dependency "rr"
26
+
27
+ # s.add_runtime_dependency "rest-client"
28
+ end
@@ -0,0 +1,7 @@
1
+ module Em
2
+ module Xmlrpc
3
+ module Client
4
+ VERSION = "1.0.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,189 @@
1
+ require "em-xmlrpc-client/version"
2
+ require "xmlrpc/client"
3
+
4
+ module XMLRPC
5
+ class Client
6
+
7
+ def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil,
8
+ user=nil, password=nil, use_ssl=nil, timeout=nil)
9
+
10
+ @http_header_extra = nil
11
+ @http_last_response = nil
12
+ @cookie = nil
13
+
14
+ @host = host || "localhost"
15
+ @path = path || "/RPC2"
16
+ @proxy_host = proxy_host
17
+ @proxy_port = proxy_port
18
+ @proxy_host ||= 'localhost' if @proxy_port != nil
19
+ @proxy_port ||= 8080 if @proxy_host != nil
20
+ @use_ssl = use_ssl || false
21
+ @timeout = timeout || 30
22
+
23
+ if use_ssl
24
+ require "net/https"
25
+ @port = port || 443
26
+ else
27
+ @port = port || 80
28
+ end
29
+
30
+ @user, @password = user, password
31
+
32
+ set_auth
33
+
34
+ # convert ports to integers
35
+ @port = @port.to_i if @port != nil
36
+ @proxy_port = @proxy_port.to_i if @proxy_port != nil
37
+
38
+ if defined?(EM) and EM.reactor_running?
39
+ require "em-http"
40
+ require "ostruct"
41
+ require "fiber"
42
+ else
43
+ # HTTP object for synchronous calls
44
+ Net::HTTP.version_1_2
45
+ @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
46
+ @http.use_ssl = @use_ssl if @use_ssl
47
+ @http.read_timeout = @timeout
48
+ @http.open_timeout = @timeout
49
+ end
50
+
51
+ @parser = nil
52
+ @create = nil
53
+ end
54
+
55
+ def do_rpc(request, async=false)
56
+ header = {
57
+ "User-Agent" => USER_AGENT,
58
+ "Content-Type" => "text/xml; charset=utf-8",
59
+ "Content-Length" => request.size.to_s,
60
+ "Connection" => (async ? "close" : "keep-alive")
61
+ }
62
+
63
+ header["Cookie"] = @cookie if @cookie
64
+ header.update(@http_header_extra) if @http_header_extra
65
+
66
+ if @auth != nil
67
+ # add authorization header
68
+ header["Authorization"] = @auth
69
+ end
70
+
71
+ @http_last_response = nil
72
+
73
+ if defined?(EM) and EM.reactor_running?
74
+ resp = do_rpc_em_http(async, request, header)
75
+ else
76
+ resp = do_rpc_net_http(async, request, header)
77
+ end
78
+
79
+ @http_last_response = resp
80
+
81
+ data = resp.body
82
+
83
+ if resp.code == "401"
84
+ # Authorization Required
85
+ raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}"
86
+ elsif resp.code[0,1] != "2"
87
+ raise "HTTP-Error: #{resp.code} #{resp.message}"
88
+ end
89
+
90
+ ct = parse_content_type(resp["Content-Type"]).first
91
+ if ct != "text/xml"
92
+ if ct == "text/html"
93
+ raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}"
94
+ else
95
+ raise "Wrong content-type (received '#{ct}' but expected 'text/xml')"
96
+ end
97
+ end
98
+
99
+ expected = resp["Content-Length"] || "<unknown>"
100
+ if data.nil? or data.size == 0
101
+ raise "Wrong size. Was #{data.size}, should be #{expected}"
102
+ elsif expected != "<unknown>" and expected.to_i != data.size and resp["Transfer-Encoding"].nil?
103
+ raise "Wrong size. Was #{data.size}, should be #{expected}"
104
+ end
105
+
106
+ set_cookies = resp.get_fields("Set-Cookie")
107
+ if set_cookies and !set_cookies.empty?
108
+ require 'webrick/cookie'
109
+ @cookie = set_cookies.collect do |set_cookie|
110
+ cookie = WEBrick::Cookie.parse_set_cookie(set_cookie)
111
+ WEBrick::Cookie.new(cookie.name, cookie.value).to_s
112
+ end.join("; ")
113
+ end
114
+
115
+ return data
116
+ end
117
+
118
+ def timeout=(new_timeout)
119
+ @timeout = new_timeout
120
+ unless defined?(EM) and EM.reactor_running?
121
+ @http.read_timeout = @timeout
122
+ @http.open_timeout = @timeout
123
+ end
124
+ end
125
+
126
+ def do_rpc_em_http(async, request, header)
127
+ fiber = Fiber.current
128
+ http = EM::HttpRequest.new("http://#{@host}:#{@port}#{@path}").post :body => request, :timeout => @timeout
129
+ http.callback{ fiber.resume }
130
+ http.errback do
131
+ # Unfortunately, we can't determine exactly what the error is using EventMachine < 1.0.
132
+ error = RuntimeError.new("connection or timeout error")
133
+ fiber.resume(error)
134
+ end
135
+
136
+ e = Fiber.yield and raise(e)
137
+
138
+ # Ducktype our response object.
139
+ resp = OpenStruct.new :code => http.response_header.http_status.to_s,
140
+ :message => http.response_header.http_reason,
141
+ :header => http.response_header.to_hash,
142
+ :body => http.response.to_s
143
+
144
+ resp.header["Content-Type"] = resp.header["CONTENT_TYPE"]
145
+ resp.header["Content-Length"] = resp.header["CONTENT_LENGTH"]
146
+ resp.header["Transfer-Encoding"] = resp.header["TRANSFER_ENCODING"]
147
+ resp.header["Set-Cookie"] = resp.header["SET_COOKIE"]
148
+
149
+ def resp.[](name)
150
+ header[name]
151
+ end
152
+ def resp.get_fields(name)
153
+ value = header[name]
154
+ value and [value].flatten
155
+ end
156
+
157
+ resp
158
+ end
159
+
160
+ def do_rpc_net_http(async, request, header)
161
+ resp = nil
162
+
163
+ if async
164
+ # use a new HTTP object for each call
165
+ Net::HTTP.version_1_2
166
+ http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
167
+ http.use_ssl = @use_ssl if @use_ssl
168
+ http.read_timeout = @timeout
169
+ http.open_timeout = @timeout
170
+
171
+ # post request
172
+ http.start {
173
+ resp = http.post2(@path, request, header)
174
+ }
175
+ else
176
+ # reuse the HTTP object for each call => connection alive is possible
177
+ # we must start connection explicitely first time so that http.request
178
+ # does not assume that we don't want keepalive
179
+ @http.start if not @http.started?
180
+
181
+ # post request
182
+ resp = @http.post2(@path, request, header)
183
+ end
184
+
185
+ resp
186
+ end
187
+
188
+ end
189
+ end
@@ -0,0 +1,53 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Fri, 29 Jul 2011 17:42:24 GMT
3
+ Server: Apache
4
+ X-Powered-By: PHP/5.2.11
5
+ Content-Length: 988
6
+ Connection: close
7
+ Content-Type: text/xml; charset=UTF-8
8
+
9
+ <?xml version="1.0" encoding="UTF-8"?>
10
+ <methodResponse>
11
+ <params>
12
+ <param>
13
+ <value><struct>
14
+ <member><name>zoneId</name>
15
+ <value><int>55</int></value>
16
+ </member>
17
+ <member><name>publisherId</name>
18
+ <value><int>6</int></value>
19
+ </member>
20
+ <member><name>zoneName</name>
21
+ <value><string>Telegraph ATW</string></value>
22
+ </member>
23
+ <member><name>type</name>
24
+ <value><int>0</int></value>
25
+ </member>
26
+ <member><name>width</name>
27
+ <value><int>150</int></value>
28
+ </member>
29
+ <member><name>height</name>
30
+ <value><int>150</int></value>
31
+ </member>
32
+ <member><name>capping</name>
33
+ <value><int>0</int></value>
34
+ </member>
35
+ <member><name>sessionCapping</name>
36
+ <value><int>0</int></value>
37
+ </member>
38
+ <member><name>block</name>
39
+ <value><int>0</int></value>
40
+ </member>
41
+ <member><name>comments</name>
42
+ <value><string></string></value>
43
+ </member>
44
+ <member><name>append</name>
45
+ <value><string></string></value>
46
+ </member>
47
+ <member><name>prepend</name>
48
+ <value><string></string></value>
49
+ </member>
50
+ </struct></value>
51
+ </param>
52
+ </params>
53
+ </methodResponse>
data/test/helper.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'eventmachine'
15
+ require 'em-http'
16
+ require 'webmock/test_unit' # This needs to come after requiring 'em-http'.
17
+ require 'rr'
18
+ require 'em-xmlrpc-client'
19
+
20
+ class Test::Unit::TestCase
21
+ include RR::Adapters::TestUnit
22
+ end
@@ -0,0 +1,36 @@
1
+ require 'helper'
2
+
3
+ class TestEmXmlrpcClient < Test::Unit::TestCase
4
+
5
+ def test_em_http
6
+ host = "localhost"
7
+ path = "api/v2/xmlrpc"
8
+ stub_request(:post, "http://#{host}/#{path}").to_return(File.read("test/data/response"))
9
+ expected = {"zoneId"=>55, "publisherId"=>6, "zoneName"=>"Telegraph ATW", "type"=>0, "width"=>150, "height"=>150, "capping"=>0, "sessionCapping"=>0, "block"=>0, "comments"=>"", "append"=>"", "prepend"=>""}
10
+
11
+ EM.run do
12
+ Fiber.new do
13
+ client = XMLRPC::Client.new2("http://#{host}/#{path}")
14
+ mock.proxy(client).do_rpc_em_http(anything, anything, anything)
15
+ mock(client).do_rpc_net_http.never
16
+ actual = client.call("ox.getZone", "phpads4e32f100507466.86347358", 54)
17
+ assert_equal expected, actual
18
+ EM.stop
19
+ end.resume
20
+ end
21
+ end
22
+
23
+ def test_net_http
24
+ host = "localhost"
25
+ path = "api/v2/xmlrpc"
26
+ stub_request(:post, "http://#{host}/#{path}").to_return(File.read("test/data/response"))
27
+ expected = {"zoneId"=>55, "publisherId"=>6, "zoneName"=>"Telegraph ATW", "type"=>0, "width"=>150, "height"=>150, "capping"=>0, "sessionCapping"=>0, "block"=>0, "comments"=>"", "append"=>"", "prepend"=>""}
28
+
29
+ client = XMLRPC::Client.new2("http://#{host}/#{path}")
30
+ mock(client).do_rpc_em_http.never
31
+ mock.proxy(client).do_rpc_net_http(anything, anything, anything)
32
+ actual = client.call("ox.getZone", "phpads4e32f100507466.86347358", 54)
33
+ assert_equal expected, actual
34
+ end
35
+
36
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-xmlrpc-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Christopher J. Bottaro
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: &70204197997120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70204197997120
25
+ - !ruby/object:Gem::Dependency
26
+ name: em-http-request
27
+ requirement: &70204197996700 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70204197996700
36
+ - !ruby/object:Gem::Dependency
37
+ name: webmock
38
+ requirement: &70204197996280 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70204197996280
47
+ - !ruby/object:Gem::Dependency
48
+ name: rr
49
+ requirement: &70204197995860 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70204197995860
58
+ description: Monkey patches Ruby's standard XMLRPC Client to use EventMachine and
59
+ fibers
60
+ email:
61
+ - cjbottaro@alumni.cs.utexas.edu
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .document
67
+ - .gitignore
68
+ - Gemfile
69
+ - Gemfile.lock
70
+ - LICENSE.txt
71
+ - README.rdoc
72
+ - Rakefile
73
+ - VERSION
74
+ - em-xmlrpc-client.gemspec
75
+ - lib/em-xmlrpc-client.rb
76
+ - lib/em-xmlrpc-client/version.rb
77
+ - test/data/response
78
+ - test/helper.rb
79
+ - test/test_em-xmlrpc-client.rb
80
+ homepage: ''
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ segments:
93
+ - 0
94
+ hash: -159327133412347017
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
102
+ - 0
103
+ hash: -159327133412347017
104
+ requirements: []
105
+ rubyforge_project: em-xmlrpc-client
106
+ rubygems_version: 1.8.11
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: Evented and fibered XMLRPC Client
110
+ test_files:
111
+ - test/data/response
112
+ - test/helper.rb
113
+ - test/test_em-xmlrpc-client.rb