gravis-typhoeus 0.1.29

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.
Files changed (44) hide show
  1. data/.gitignore +2 -0
  2. data/README.textile +301 -0
  3. data/Rakefile +39 -0
  4. data/VERSION +1 -0
  5. data/benchmarks/profile.rb +25 -0
  6. data/benchmarks/vs_nethttp.rb +35 -0
  7. data/examples/twitter.rb +21 -0
  8. data/ext/typhoeus/.gitignore +5 -0
  9. data/ext/typhoeus/Makefile +157 -0
  10. data/ext/typhoeus/extconf.rb +65 -0
  11. data/ext/typhoeus/native.c +11 -0
  12. data/ext/typhoeus/native.h +21 -0
  13. data/ext/typhoeus/typhoeus_easy.c +207 -0
  14. data/ext/typhoeus/typhoeus_easy.h +19 -0
  15. data/ext/typhoeus/typhoeus_multi.c +225 -0
  16. data/ext/typhoeus/typhoeus_multi.h +16 -0
  17. data/lib/typhoeus/.gitignore +1 -0
  18. data/lib/typhoeus/easy.rb +322 -0
  19. data/lib/typhoeus/filter.rb +28 -0
  20. data/lib/typhoeus/hydra.rb +227 -0
  21. data/lib/typhoeus/multi.rb +35 -0
  22. data/lib/typhoeus/remote.rb +306 -0
  23. data/lib/typhoeus/remote_method.rb +108 -0
  24. data/lib/typhoeus/remote_proxy_object.rb +48 -0
  25. data/lib/typhoeus/request.rb +124 -0
  26. data/lib/typhoeus/response.rb +49 -0
  27. data/lib/typhoeus/service.rb +20 -0
  28. data/lib/typhoeus.rb +55 -0
  29. data/profilers/valgrind.rb +24 -0
  30. data/spec/fixtures/result_set.xml +60 -0
  31. data/spec/servers/app.rb +73 -0
  32. data/spec/spec.opts +2 -0
  33. data/spec/spec_helper.rb +11 -0
  34. data/spec/typhoeus/easy_spec.rb +228 -0
  35. data/spec/typhoeus/filter_spec.rb +35 -0
  36. data/spec/typhoeus/hydra_spec.rb +311 -0
  37. data/spec/typhoeus/multi_spec.rb +74 -0
  38. data/spec/typhoeus/remote_method_spec.rb +141 -0
  39. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  40. data/spec/typhoeus/remote_spec.rb +695 -0
  41. data/spec/typhoeus/request_spec.rb +169 -0
  42. data/spec/typhoeus/response_spec.rb +63 -0
  43. data/typhoeus.gemspec +112 -0
  44. metadata +203 -0
@@ -0,0 +1,306 @@
1
+ module Typhoeus
2
+ USER_AGENT = "Typhoeus - http://github.com/pauldix/typhoeus/tree/master"
3
+
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ class MockExpectedError < StandardError; end
9
+
10
+ module ClassMethods
11
+ def allow_net_connect
12
+ @allow_net_connect = true if @allow_net_connect.nil?
13
+ @allow_net_connect
14
+ end
15
+
16
+ def allow_net_connect=(value)
17
+ @allow_net_connect = value
18
+ end
19
+
20
+ def mock(method, args = {})
21
+ @remote_mocks ||= {}
22
+ @remote_mocks[method] ||= {}
23
+ args[:code] ||= 200
24
+ args[:body] ||= ""
25
+ args[:headers] ||= ""
26
+ args[:time] ||= 0
27
+ url = args.delete(:url)
28
+ url ||= :catch_all
29
+ params = args.delete(:params)
30
+
31
+ key = mock_key_for(url, params)
32
+
33
+ @remote_mocks[method][key] = args
34
+ end
35
+
36
+ # Returns a key for a given URL and passed in
37
+ # set of Typhoeus options to be used to store/retrieve
38
+ # a corresponding mock.
39
+ def mock_key_for(url, params = nil)
40
+ if url == :catch_all
41
+ url
42
+ else
43
+ key = url
44
+ if params and !params.empty?
45
+ key += flatten_and_sort_hash(params).to_s
46
+ end
47
+ key
48
+ end
49
+ end
50
+
51
+ def flatten_and_sort_hash(params)
52
+ params = params.dup
53
+
54
+ # Flatten any sub-hashes to a single string.
55
+ params.keys.each do |key|
56
+ if params[key].is_a?(Hash)
57
+ params[key] = params[key].sort_by { |k, v| k.to_s.downcase }.to_s
58
+ end
59
+ end
60
+
61
+ params.sort_by { |k, v| k.to_s.downcase }
62
+ end
63
+
64
+ def get_mock(method, url, options)
65
+ return nil unless @remote_mocks
66
+ if @remote_mocks.has_key? method
67
+ extra_response_args = { :requested_http_method => method,
68
+ :requested_url => url,
69
+ :start_time => Time.now }
70
+ mock_key = mock_key_for(url, options[:params])
71
+ if @remote_mocks[method].has_key? mock_key
72
+ get_mock_and_run_handlers(method,
73
+ @remote_mocks[method][mock_key].merge(
74
+ extra_response_args),
75
+ options)
76
+ elsif @remote_mocks[method].has_key? :catch_all
77
+ get_mock_and_run_handlers(method,
78
+ @remote_mocks[method][:catch_all].merge(
79
+ extra_response_args),
80
+ options)
81
+ else
82
+ nil
83
+ end
84
+ else
85
+ nil
86
+ end
87
+ end
88
+
89
+ def enforce_allow_net_connect!(http_verb, url, params = nil)
90
+ if !allow_net_connect
91
+ message = "Real HTTP connections are disabled. Unregistered request: " <<
92
+ "#{http_verb.to_s.upcase} #{url}\n" <<
93
+ " Try: mock(:#{http_verb}, :url => \"#{url}\""
94
+ if params
95
+ message << ",\n :params => #{params.inspect}"
96
+ end
97
+
98
+ message << ")"
99
+
100
+ raise MockExpectedError, message
101
+ end
102
+ end
103
+
104
+ def check_expected_headers!(response_args, options)
105
+ missing_headers = {}
106
+
107
+ response_args[:expected_headers].each do |key, value|
108
+ if options[:headers].nil?
109
+ missing_headers[key] = [value, nil]
110
+ elsif ((options[:headers][key] && value != :anything) &&
111
+ options[:headers][key] != value)
112
+
113
+ missing_headers[key] = [value, options[:headers][key]]
114
+ end
115
+ end
116
+
117
+ unless missing_headers.empty?
118
+ raise headers_error_summary(response_args, options, missing_headers, 'expected')
119
+ end
120
+ end
121
+
122
+ def check_unexpected_headers!(response_args, options)
123
+ bad_headers = {}
124
+ response_args[:unexpected_headers].each do |key, value|
125
+ if (options[:headers][key] && value == :anything) ||
126
+ (options[:headers][key] == value)
127
+ bad_headers[key] = [value, options[:headers][key]]
128
+ end
129
+ end
130
+
131
+ unless bad_headers.empty?
132
+ raise headers_error_summary(response_args, options, bad_headers, 'did not expect')
133
+ end
134
+ end
135
+
136
+ def headers_error_summary(response_args, options, missing_headers, lead_in)
137
+ error = "#{lead_in} the following headers: #{response_args[:expected_headers].inspect}, but received: #{options[:headers].inspect}\n\n"
138
+ error << "Differences:\n"
139
+ error << "------------\n"
140
+ missing_headers.each do |key, values|
141
+ error << " - #{key}: #{lead_in} #{values[0].inspect}, got #{values[1].inspect}\n"
142
+ end
143
+
144
+ error
145
+ end
146
+ private :headers_error_summary
147
+
148
+ def get_mock_and_run_handlers(method, response_args, options)
149
+ response = Response.new(response_args)
150
+
151
+ if response_args.has_key? :expected_body
152
+ raise "#{method} expected body of \"#{response_args[:expected_body]}\" but received #{options[:body]}" if response_args[:expected_body] != options[:body]
153
+ end
154
+
155
+ if response_args.has_key? :expected_headers
156
+ check_expected_headers!(response_args, options)
157
+ end
158
+
159
+ if response_args.has_key? :unexpected_headers
160
+ check_unexpected_headers!(response_args, options)
161
+ end
162
+
163
+ if response.code >= 200 && response.code < 300 && options.has_key?(:on_success)
164
+ response = options[:on_success].call(response)
165
+ elsif options.has_key?(:on_failure)
166
+ response = options[:on_failure].call(response)
167
+ end
168
+
169
+ encode_nil_response(response)
170
+ end
171
+
172
+ [:get, :post, :put, :delete].each do |method|
173
+ line = __LINE__ + 2 # get any errors on the correct line num
174
+ code = <<-SRC
175
+ def #{method.to_s}(url, options = {})
176
+ mock_object = get_mock(:#{method.to_s}, url, options)
177
+ unless mock_object.nil?
178
+ decode_nil_response(mock_object)
179
+ else
180
+ enforce_allow_net_connect!(:#{method.to_s}, url, options[:params])
181
+ remote_proxy_object(url, :#{method.to_s}, options)
182
+ end
183
+ end
184
+ SRC
185
+ module_eval(code, "./lib/typhoeus/remote.rb", line)
186
+ end
187
+
188
+ def remote_proxy_object(url, method, options)
189
+ easy = Typhoeus.get_easy_object
190
+
191
+ easy.url = url
192
+ easy.method = method
193
+ easy.headers = options[:headers] if options.has_key?(:headers)
194
+ easy.headers["User-Agent"] = (options[:user_agent] || Typhoeus::USER_AGENT)
195
+ easy.params = options[:params] if options[:params]
196
+ easy.request_body = options[:body] if options[:body]
197
+ easy.timeout = options[:timeout] if options[:timeout]
198
+ easy.set_headers
199
+
200
+ proxy = Typhoeus::RemoteProxyObject.new(clear_memoized_proxy_objects, easy, options)
201
+ set_memoized_proxy_object(method, url, options, proxy)
202
+ end
203
+
204
+ def remote_defaults(options)
205
+ @remote_defaults ||= {}
206
+ @remote_defaults.merge!(options) if options
207
+ @remote_defaults
208
+ end
209
+
210
+ # If we get subclassed, make sure that child inherits the remote defaults
211
+ # of the parent class.
212
+ def inherited(child)
213
+ child.__send__(:remote_defaults, @remote_defaults)
214
+ end
215
+
216
+ def call_remote_method(method_name, args)
217
+ m = @remote_methods[method_name]
218
+
219
+ base_uri = args.delete(:base_uri) || m.base_uri || ""
220
+
221
+ if args.has_key? :path
222
+ path = args.delete(:path)
223
+ else
224
+ path = m.interpolate_path_with_arguments(args)
225
+ end
226
+ path ||= ""
227
+
228
+ http_method = m.http_method
229
+ url = base_uri + path
230
+ options = m.merge_options(args)
231
+
232
+ # proxy_object = memoized_proxy_object(http_method, url, options)
233
+ # return proxy_object unless proxy_object.nil?
234
+ #
235
+ # if m.cache_responses?
236
+ # object = @cache.get(get_memcache_response_key(method_name, args))
237
+ # if object
238
+ # set_memoized_proxy_object(http_method, url, options, object)
239
+ # return object
240
+ # end
241
+ # end
242
+
243
+ proxy = memoized_proxy_object(http_method, url, options)
244
+ unless proxy
245
+ if m.cache_responses?
246
+ options[:cache] = @cache
247
+ options[:cache_key] = get_memcache_response_key(method_name, args)
248
+ options[:cache_timeout] = m.cache_ttl
249
+ end
250
+ proxy = send(http_method, url, options)
251
+ end
252
+ proxy
253
+ end
254
+
255
+ def set_memoized_proxy_object(http_method, url, options, object)
256
+ @memoized_proxy_objects ||= {}
257
+ @memoized_proxy_objects["#{http_method}_#{url}_#{options.to_s}"] = object
258
+ end
259
+
260
+ def memoized_proxy_object(http_method, url, options)
261
+ @memoized_proxy_objects ||= {}
262
+ @memoized_proxy_objects["#{http_method}_#{url}_#{options.to_s}"]
263
+ end
264
+
265
+ def clear_memoized_proxy_objects
266
+ lambda { @memoized_proxy_objects = {} }
267
+ end
268
+
269
+ def get_memcache_response_key(remote_method_name, args)
270
+ result = "#{remote_method_name.to_s}-#{args.to_s}"
271
+ (Digest::SHA2.new << result).to_s
272
+ end
273
+
274
+ def cache=(cache)
275
+ @cache = cache
276
+ end
277
+
278
+ def define_remote_method(name, args = {})
279
+ @remote_defaults ||= {}
280
+ args[:method] ||= @remote_defaults[:method]
281
+ args[:on_success] ||= @remote_defaults[:on_success]
282
+ args[:on_failure] ||= @remote_defaults[:on_failure]
283
+ args[:base_uri] ||= @remote_defaults[:base_uri]
284
+ args[:path] ||= @remote_defaults[:path]
285
+ m = RemoteMethod.new(args)
286
+
287
+ @remote_methods ||= {}
288
+ @remote_methods[name] = m
289
+
290
+ class_eval <<-SRC
291
+ def self.#{name.to_s}(args = {})
292
+ call_remote_method(:#{name.to_s}, args)
293
+ end
294
+ SRC
295
+ end
296
+
297
+ private
298
+ def encode_nil_response(response)
299
+ response == nil ? :__nil__ : response
300
+ end
301
+
302
+ def decode_nil_response(response)
303
+ response == :__nil__ ? nil : response
304
+ end
305
+ end # ClassMethods
306
+ end
@@ -0,0 +1,108 @@
1
+ module Typhoeus
2
+ class RemoteMethod
3
+ attr_accessor :http_method, :options, :base_uri, :path, :on_success, :on_failure, :cache_ttl
4
+
5
+ def initialize(options = {})
6
+ @http_method = options.delete(:method) || :get
7
+ @options = options
8
+ @base_uri = options.delete(:base_uri)
9
+ @path = options.delete(:path)
10
+ @on_success = options[:on_success]
11
+ @on_failure = options[:on_failure]
12
+ @cache_responses = options.delete(:cache_responses)
13
+ @memoize_responses = options.delete(:memoize_responses) || @cache_responses
14
+ @cache_ttl = @cache_responses == true ? 0 : @cache_responses
15
+ @keys = nil
16
+
17
+ clear_cache
18
+ end
19
+
20
+ def cache_responses?
21
+ @cache_responses
22
+ end
23
+
24
+ def memoize_responses?
25
+ @memoize_responses
26
+ end
27
+
28
+ def args_options_key(args, options)
29
+ "#{args.to_s}+#{options.to_s}"
30
+ end
31
+
32
+ def calling(args, options)
33
+ @called_methods[args_options_key(args, options)] = true
34
+ end
35
+
36
+ def already_called?(args, options)
37
+ @called_methods.has_key? args_options_key(args, options)
38
+ end
39
+
40
+ def add_response_block(block, args, options)
41
+ @response_blocks[args_options_key(args, options)] << block
42
+ end
43
+
44
+ def call_response_blocks(result, args, options)
45
+ key = args_options_key(args, options)
46
+ @response_blocks[key].each {|block| block.call(result)}
47
+ @response_blocks.delete(key)
48
+ @called_methods.delete(key)
49
+ end
50
+
51
+ def clear_cache
52
+ @response_blocks = Hash.new {|h, k| h[k] = []}
53
+ @called_methods = {}
54
+ end
55
+
56
+ def merge_options(new_options)
57
+ merged = options.merge(new_options)
58
+ if options.has_key?(:params) && new_options.has_key?(:params)
59
+ merged[:params] = options[:params].merge(new_options[:params])
60
+ end
61
+ argument_names.each {|a| merged.delete(a)}
62
+ merged.delete(:on_success) if merged[:on_success].nil?
63
+ merged.delete(:on_failure) if merged[:on_failure].nil?
64
+ merged
65
+ end
66
+
67
+ def interpolate_path_with_arguments(args)
68
+ interpolated_path = @path
69
+ argument_names.each do |arg|
70
+ interpolated_path = interpolated_path.gsub(":#{arg}", args[arg].to_s)
71
+ end
72
+ interpolated_path
73
+ end
74
+
75
+ def argument_names
76
+ return @keys if @keys
77
+ pattern, keys = compile(@path)
78
+ @keys = keys.collect {|k| k.to_sym}
79
+ end
80
+
81
+ # rippped from Sinatra. clean up stuff we don't need later
82
+ def compile(path)
83
+ path ||= ""
84
+ keys = []
85
+ if path.respond_to? :to_str
86
+ special_chars = %w{. + ( )}
87
+ pattern =
88
+ path.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
89
+ case match
90
+ when "*"
91
+ keys << 'splat'
92
+ "(.*?)"
93
+ when *special_chars
94
+ Regexp.escape(match)
95
+ else
96
+ keys << $2[1..-1]
97
+ "([^/?&#]+)"
98
+ end
99
+ end
100
+ [/^#{pattern}$/, keys]
101
+ elsif path.respond_to? :match
102
+ [path, keys]
103
+ else
104
+ raise TypeError, path
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,48 @@
1
+ module Typhoeus
2
+ class RemoteProxyObject
3
+ instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
4
+
5
+ def initialize(clear_memoized_store_proc, easy, options = {})
6
+ @clear_memoized_store_proc = clear_memoized_store_proc
7
+ @easy = easy
8
+ @success = options[:on_success]
9
+ @failure = options[:on_failure]
10
+ @cache = options.delete(:cache)
11
+ @cache_key = options.delete(:cache_key)
12
+ @timeout = options.delete(:cache_timeout)
13
+ Typhoeus.add_easy_request(@easy)
14
+ end
15
+
16
+ def method_missing(sym, *args, &block)
17
+ unless @proxied_object
18
+ if @cache && @cache_key
19
+ @proxied_object = @cache.get(@cache_key) rescue nil
20
+ end
21
+
22
+ unless @proxied_object
23
+ Typhoeus.perform_easy_requests
24
+ response = Response.new(:code => @easy.response_code,
25
+ :headers => @easy.response_header,
26
+ :body => @easy.response_body,
27
+ :time => @easy.total_time_taken,
28
+ :requested_url => @easy.url,
29
+ :requested_http_method => @easy.method,
30
+ :start_time => @easy.start_time)
31
+ if @easy.response_code >= 200 && @easy.response_code < 300
32
+ Typhoeus.release_easy_object(@easy)
33
+ @proxied_object = @success.nil? ? response : @success.call(response)
34
+
35
+ if @cache && @cache_key
36
+ @cache.set(@cache_key, @proxied_object, @timeout)
37
+ end
38
+ else
39
+ @proxied_object = @failure.nil? ? response : @failure.call(response)
40
+ end
41
+ @clear_memoized_store_proc.call
42
+ end
43
+ end
44
+
45
+ @proxied_object.__send__(sym, *args, &block)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,124 @@
1
+ module Typhoeus
2
+ class Request
3
+ attr_accessor :method, :params, :body, :headers, :timeout, :user_agent, :response, :cache_timeout, :follow_location, :max_redirects, :proxy, :disable_ssl_peer_verification
4
+ attr_reader :url
5
+
6
+ def initialize(url, options = {})
7
+ @method = options[:method] || :get
8
+ @params = options[:params]
9
+ @body = options[:body]
10
+ @timeout = options[:timeout]
11
+ @headers = options[:headers] || {}
12
+ @user_agent = options[:user_agent] || Typhoeus::USER_AGENT
13
+ @cache_timeout = options[:cache_timeout]
14
+ @follow_location = options[:follow_location]
15
+ @max_redirects = options[:max_redirects]
16
+ @proxy = options[:proxy]
17
+ @disable_ssl_peer_verification = options[:disable_ssl_peer_verification]
18
+
19
+ if @method == :post
20
+ @url = url
21
+ else
22
+ @url = @params ? "#{url}?#{params_string}" : url
23
+ end
24
+ @on_complete = nil
25
+ @after_complete = nil
26
+ @handled_response = nil
27
+ end
28
+
29
+ def host
30
+ slash_location = @url.index('/', 8)
31
+ if slash_location
32
+ @url.slice(0, slash_location)
33
+ else
34
+ query_string_location = @url.index('?')
35
+ return query_string_location ? @url.slice(0, query_string_location) : @url
36
+ end
37
+ end
38
+
39
+ def headers
40
+ @headers["User-Agent"] = @user_agent
41
+ @headers
42
+ end
43
+
44
+ def params_string
45
+ params.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |k|
46
+ value = params[k]
47
+ if value.is_a? Hash
48
+ value.keys.collect {|sk| Rack::Utils.escape("#{k}[#{sk}]") + "=" + Rack::Utils.escape(value[sk].to_s)}
49
+ elsif value.is_a? Array
50
+ key = Rack::Utils.escape(k.to_s)
51
+ value.collect { |v| "#{key}=#{Rack::Utils.escape(v.to_s)}" }.join('&')
52
+ else
53
+ "#{Rack::Utils.escape(k.to_s)}=#{Rack::Utils.escape(params[k].to_s)}"
54
+ end
55
+ end.flatten.join("&")
56
+ end
57
+
58
+ def on_complete(&block)
59
+ @on_complete = block
60
+ end
61
+
62
+ def on_complete=(proc)
63
+ @on_complete = proc
64
+ end
65
+
66
+ def after_complete(&block)
67
+ @after_complete = block
68
+ end
69
+
70
+ def after_complete=(proc)
71
+ @after_complete = proc
72
+ end
73
+
74
+ def call_handlers
75
+ if @on_complete
76
+ @handled_response = @on_complete.call(response)
77
+ call_after_complete
78
+ end
79
+ end
80
+
81
+ def call_after_complete
82
+ @after_complete.call(@handled_response) if @after_complete
83
+ end
84
+
85
+ def handled_response=(val)
86
+ @handled_response = val
87
+ end
88
+
89
+ def handled_response
90
+ @handled_response || response
91
+ end
92
+
93
+ def cache_key
94
+ Digest::SHA1.hexdigest(url)
95
+ end
96
+
97
+ def self.run(url, params)
98
+ r = new(url, params)
99
+ Typhoeus::Hydra.hydra.queue r
100
+ Typhoeus::Hydra.hydra.run
101
+ r.response
102
+ end
103
+
104
+ def self.get(url, params = {})
105
+ run(url, params.merge(:method => :get))
106
+ end
107
+
108
+ def self.post(url, params = {})
109
+ run(url, params.merge(:method => :post))
110
+ end
111
+
112
+ def self.put(url, params = {})
113
+ run(url, params.merge(:method => :put))
114
+ end
115
+
116
+ def self.delete(url, params = {})
117
+ run(url, params.merge(:method => :delete))
118
+ end
119
+
120
+ def self.head(url, params = {})
121
+ run(url, params.merge(:method => :head))
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,49 @@
1
+ module Typhoeus
2
+ class Response
3
+ attr_accessor :request
4
+ attr_reader :code, :headers, :body, :time,
5
+ :requested_url, :requested_remote_method,
6
+ :requested_http_method, :start_time,
7
+ :effective_url
8
+
9
+ def initialize(params = {})
10
+ @code = params[:code]
11
+ @headers = params[:headers]
12
+ @body = params[:body]
13
+ @time = params[:time]
14
+ @requested_url = params[:requested_url]
15
+ @requested_http_method = params[:requested_http_method]
16
+ @start_time = params[:start_time]
17
+ @request = params[:request]
18
+ @effective_url = params[:effective_url]
19
+ end
20
+
21
+ def headers_hash
22
+ headers.split("\n").map {|o| o.strip}.inject({}) do |hash, o|
23
+ if o.empty?
24
+ hash
25
+ else
26
+ i = o.index(":") || o.size
27
+ key = o.slice(0, i)
28
+ value = o.slice(i + 1, o.size)
29
+ value = value.strip unless value.nil?
30
+ if hash.has_key? key
31
+ hash[key] = [hash[key], value].flatten
32
+ else
33
+ hash[key] = value
34
+ end
35
+
36
+ hash
37
+ end
38
+ end
39
+ end
40
+
41
+ def success?
42
+ @code >= 200 && @code < 300
43
+ end
44
+
45
+ def modified?
46
+ @code != 304
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ module Typhoeus
2
+ class Service
3
+ def initialize(host, port)
4
+ @host = host
5
+ @port = port
6
+ end
7
+
8
+ def get(resource, params)
9
+ end
10
+
11
+ def put(resource, params)
12
+ end
13
+
14
+ def post(resource, params)
15
+ end
16
+
17
+ def delete(resource, params)
18
+ end
19
+ end
20
+ end
data/lib/typhoeus.rb ADDED
@@ -0,0 +1,55 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__))
2
+
3
+ require 'rack/utils'
4
+ require 'digest/sha2'
5
+ require 'typhoeus/easy'
6
+ require 'typhoeus/multi'
7
+ require 'typhoeus/native'
8
+ require 'typhoeus/filter'
9
+ require 'typhoeus/remote_method'
10
+ require 'typhoeus/remote'
11
+ require 'typhoeus/remote_proxy_object'
12
+ require 'typhoeus/response'
13
+ require 'typhoeus/request'
14
+ require 'typhoeus/hydra'
15
+
16
+ module Typhoeus
17
+ VERSION = File.read(File.dirname(__FILE__) + "/../VERSION").chomp
18
+
19
+ def self.easy_object_pool
20
+ @easy_objects ||= []
21
+ end
22
+
23
+ def self.init_easy_object_pool
24
+ 20.times do
25
+ easy_object_pool << Typhoeus::Easy.new
26
+ end
27
+ end
28
+
29
+ def self.release_easy_object(easy)
30
+ easy.reset
31
+ easy_object_pool << easy
32
+ end
33
+
34
+ def self.get_easy_object
35
+ if easy_object_pool.empty?
36
+ Typhoeus::Easy.new
37
+ else
38
+ easy_object_pool.pop
39
+ end
40
+ end
41
+
42
+ def self.add_easy_request(easy_object)
43
+ Thread.current[:curl_multi] ||= Typhoeus::Multi.new
44
+ Thread.current[:curl_multi].add(easy_object)
45
+ end
46
+
47
+ def self.perform_easy_requests
48
+ multi = Thread.current[:curl_multi]
49
+ start_time = Time.now
50
+ multi.easy_handles.each do |easy|
51
+ easy.start_time = start_time
52
+ end
53
+ multi.perform
54
+ end
55
+ end