typhoeus 0.4.2 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +4 -0
- data/.travis.yml +26 -0
- data/CHANGELOG.md +341 -28
- data/CONTRIBUTING.md +20 -0
- data/Gemfile +31 -2
- data/Guardfile +9 -0
- data/LICENSE +1 -1
- data/README.md +486 -357
- data/Rakefile +21 -12
- data/UPGRADE.md +55 -0
- data/lib/rack/typhoeus/middleware/params_decoder/helper.rb +76 -0
- data/lib/rack/typhoeus/middleware/params_decoder.rb +57 -0
- data/lib/rack/typhoeus.rb +1 -0
- data/lib/typhoeus/adapters/faraday.rb +180 -0
- data/lib/typhoeus/cache/dalli.rb +28 -0
- data/lib/typhoeus/cache/rails.rb +28 -0
- data/lib/typhoeus/cache/redis.rb +35 -0
- data/lib/typhoeus/config.rb +69 -0
- data/lib/typhoeus/easy_factory.rb +180 -0
- data/lib/typhoeus/errors/no_stub.rb +12 -0
- data/lib/typhoeus/errors/typhoeus_error.rb +8 -0
- data/lib/typhoeus/errors.rb +9 -0
- data/lib/typhoeus/expectation.rb +217 -0
- data/lib/typhoeus/hydra/addable.rb +23 -0
- data/lib/typhoeus/hydra/before.rb +31 -0
- data/lib/typhoeus/hydra/block_connection.rb +35 -0
- data/lib/typhoeus/hydra/cacheable.rb +15 -0
- data/lib/typhoeus/hydra/memoizable.rb +56 -0
- data/lib/typhoeus/hydra/queueable.rb +83 -0
- data/lib/typhoeus/hydra/runnable.rb +19 -0
- data/lib/typhoeus/hydra/stubbable.rb +28 -0
- data/lib/typhoeus/hydra.rb +84 -236
- data/lib/typhoeus/pool.rb +70 -0
- data/lib/typhoeus/railtie.rb +12 -0
- data/lib/typhoeus/request/actions.rb +125 -0
- data/lib/typhoeus/request/before.rb +30 -0
- data/lib/typhoeus/request/block_connection.rb +52 -0
- data/lib/typhoeus/request/cacheable.rb +38 -0
- data/lib/typhoeus/request/callbacks.rb +151 -0
- data/lib/typhoeus/request/marshal.rb +22 -0
- data/lib/typhoeus/request/memoizable.rb +38 -0
- data/lib/typhoeus/request/operations.rb +40 -0
- data/lib/typhoeus/request/responseable.rb +29 -0
- data/lib/typhoeus/request/streamable.rb +34 -0
- data/lib/typhoeus/request/stubbable.rb +30 -0
- data/lib/typhoeus/request.rb +186 -231
- data/lib/typhoeus/response/cacheable.rb +14 -0
- data/lib/typhoeus/response/header.rb +105 -0
- data/lib/typhoeus/response/informations.rb +248 -0
- data/lib/typhoeus/response/status.rb +106 -0
- data/lib/typhoeus/response.rb +60 -115
- data/lib/typhoeus/version.rb +3 -1
- data/lib/typhoeus.rb +126 -39
- data/perf/profile.rb +14 -0
- data/perf/vs_nethttp.rb +64 -0
- data/spec/rack/typhoeus/middleware/params_decoder/helper_spec.rb +156 -0
- data/spec/rack/typhoeus/middleware/params_decoder_spec.rb +31 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/localhost_server.rb +94 -0
- data/spec/support/memory_cache.rb +15 -0
- data/spec/support/server.rb +116 -0
- data/spec/typhoeus/adapters/faraday_spec.rb +339 -0
- data/spec/typhoeus/cache/dalli_spec.rb +41 -0
- data/spec/typhoeus/cache/redis_spec.rb +41 -0
- data/spec/typhoeus/config_spec.rb +15 -0
- data/spec/typhoeus/easy_factory_spec.rb +143 -0
- data/spec/typhoeus/errors/no_stub_spec.rb +13 -0
- data/spec/typhoeus/expectation_spec.rb +280 -0
- data/spec/typhoeus/hydra/addable_spec.rb +22 -0
- data/spec/typhoeus/hydra/before_spec.rb +98 -0
- data/spec/typhoeus/hydra/block_connection_spec.rb +18 -0
- data/spec/typhoeus/hydra/cacheable_spec.rb +88 -0
- data/spec/typhoeus/hydra/memoizable_spec.rb +53 -0
- data/spec/typhoeus/hydra/queueable_spec.rb +98 -0
- data/spec/typhoeus/hydra/runnable_spec.rb +137 -0
- data/spec/typhoeus/hydra/stubbable_spec.rb +48 -0
- data/spec/typhoeus/hydra_spec.rb +22 -0
- data/spec/typhoeus/pool_spec.rb +137 -0
- data/spec/typhoeus/request/actions_spec.rb +19 -0
- data/spec/typhoeus/request/before_spec.rb +93 -0
- data/spec/typhoeus/request/block_connection_spec.rb +75 -0
- data/spec/typhoeus/request/cacheable_spec.rb +94 -0
- data/spec/typhoeus/request/callbacks_spec.rb +91 -0
- data/spec/typhoeus/request/marshal_spec.rb +60 -0
- data/spec/typhoeus/request/memoizable_spec.rb +34 -0
- data/spec/typhoeus/request/operations_spec.rb +101 -0
- data/spec/typhoeus/request/responseable_spec.rb +13 -0
- data/spec/typhoeus/request/stubbable_spec.rb +45 -0
- data/spec/typhoeus/request_spec.rb +232 -0
- data/spec/typhoeus/response/header_spec.rb +147 -0
- data/spec/typhoeus/response/informations_spec.rb +283 -0
- data/spec/typhoeus/response/status_spec.rb +256 -0
- data/spec/typhoeus/response_spec.rb +100 -0
- data/spec/typhoeus_spec.rb +105 -0
- data/typhoeus.gemspec +25 -0
- metadata +146 -158
- data/lib/typhoeus/curl.rb +0 -453
- data/lib/typhoeus/easy/auth.rb +0 -14
- data/lib/typhoeus/easy/callbacks.rb +0 -33
- data/lib/typhoeus/easy/ffi_helper.rb +0 -61
- data/lib/typhoeus/easy/infos.rb +0 -90
- data/lib/typhoeus/easy/options.rb +0 -115
- data/lib/typhoeus/easy/proxy.rb +0 -20
- data/lib/typhoeus/easy/ssl.rb +0 -82
- data/lib/typhoeus/easy.rb +0 -115
- data/lib/typhoeus/filter.rb +0 -28
- data/lib/typhoeus/form.rb +0 -61
- data/lib/typhoeus/header.rb +0 -54
- data/lib/typhoeus/hydra/callbacks.rb +0 -24
- data/lib/typhoeus/hydra/connect_options.rb +0 -61
- data/lib/typhoeus/hydra/stubbing.rb +0 -68
- data/lib/typhoeus/hydra_mock.rb +0 -131
- data/lib/typhoeus/multi.rb +0 -146
- data/lib/typhoeus/param_processor.rb +0 -43
- data/lib/typhoeus/remote.rb +0 -306
- data/lib/typhoeus/remote_method.rb +0 -108
- data/lib/typhoeus/remote_proxy_object.rb +0 -50
- data/lib/typhoeus/utils.rb +0 -50
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Typhoeus
|
4
|
+
|
5
|
+
# This is a Factory for easies to be used in the hydra.
|
6
|
+
# Before an easy is ready to be added to a multi the
|
7
|
+
# on_complete callback to be set.
|
8
|
+
# This is done by this class.
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
class EasyFactory
|
12
|
+
|
13
|
+
RENAMED_OPTIONS = {
|
14
|
+
:auth_method => :httpauth,
|
15
|
+
:connect_timeout => :connecttimeout,
|
16
|
+
:encoding => :accept_encoding,
|
17
|
+
:follow_location => :followlocation,
|
18
|
+
:max_redirects => :maxredirs,
|
19
|
+
:proxy_type => :proxytype,
|
20
|
+
:ssl_cacert => :cainfo,
|
21
|
+
:ssl_capath => :capath,
|
22
|
+
:ssl_cert => :sslcert,
|
23
|
+
:ssl_cert_type => :sslcerttype,
|
24
|
+
:ssl_key => :sslkey,
|
25
|
+
:ssl_key_password => :keypasswd,
|
26
|
+
:ssl_key_type => :sslkeytype,
|
27
|
+
:ssl_version => :sslversion,
|
28
|
+
}
|
29
|
+
|
30
|
+
CHANGED_OPTIONS = {
|
31
|
+
:disable_ssl_host_verification => :ssl_verifyhost,
|
32
|
+
:disable_ssl_peer_verification => :ssl_verifypeer,
|
33
|
+
:proxy_auth_method => :proxyauth,
|
34
|
+
}
|
35
|
+
|
36
|
+
REMOVED_OPTIONS = Set.new([:cache_key_basis, :cache_timeout, :user_agent])
|
37
|
+
|
38
|
+
SANITIZE_IGNORE = Set.new([:method, :cache_ttl, :cache])
|
39
|
+
SANITIZE_TIMEOUT = Set.new([:timeout_ms, :connecttimeout_ms])
|
40
|
+
|
41
|
+
# Returns the request provided.
|
42
|
+
#
|
43
|
+
# @return [ Typhoeus::Request ]
|
44
|
+
attr_reader :request
|
45
|
+
|
46
|
+
# Returns the hydra provided.
|
47
|
+
#
|
48
|
+
# @return [ Typhoeus::Hydra ]
|
49
|
+
attr_reader :hydra
|
50
|
+
|
51
|
+
# Create an easy factory.
|
52
|
+
#
|
53
|
+
# @example Create easy factory.
|
54
|
+
# Typhoeus::Hydra::EasyFactory.new(request, hydra)
|
55
|
+
#
|
56
|
+
# @param [ Request ] request The request to build an easy for.
|
57
|
+
# @param [ Hydra ] hydra The hydra to build an easy for.
|
58
|
+
def initialize(request, hydra = nil)
|
59
|
+
@request = request
|
60
|
+
@hydra = hydra
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return the easy in question.
|
64
|
+
#
|
65
|
+
# @example Return easy.
|
66
|
+
# easy_factory.easy
|
67
|
+
#
|
68
|
+
# @return [ Ethon::Easy ] The easy.
|
69
|
+
def easy
|
70
|
+
@easy ||= Typhoeus::Pool.get
|
71
|
+
end
|
72
|
+
|
73
|
+
# Fabricated easy.
|
74
|
+
#
|
75
|
+
# @example Prepared easy.
|
76
|
+
# easy_factory.get
|
77
|
+
#
|
78
|
+
# @return [ Ethon::Easy ] The easy.
|
79
|
+
def get
|
80
|
+
begin
|
81
|
+
easy.http_request(
|
82
|
+
request.base_url.to_s,
|
83
|
+
request.options.fetch(:method, :get),
|
84
|
+
sanitize(request.options)
|
85
|
+
)
|
86
|
+
rescue Ethon::Errors::InvalidOption => e
|
87
|
+
help = provide_help(e.message.match(/:\s(\w+)/)[1])
|
88
|
+
raise $!, "#{$!}#{help}", $!.backtrace
|
89
|
+
end
|
90
|
+
set_callback
|
91
|
+
easy
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def sanitize(options)
|
97
|
+
# set nosignal to true by default
|
98
|
+
# this improves thread safety and timeout behavior
|
99
|
+
sanitized = {:nosignal => true}
|
100
|
+
options.each do |k,v|
|
101
|
+
s = k.to_sym
|
102
|
+
next if SANITIZE_IGNORE.include?(s)
|
103
|
+
if new_option = RENAMED_OPTIONS[k.to_sym]
|
104
|
+
warn("Deprecated option #{k}. Please use #{new_option} instead.")
|
105
|
+
sanitized[new_option] = v
|
106
|
+
# sanitize timeouts
|
107
|
+
elsif SANITIZE_TIMEOUT.include?(s)
|
108
|
+
if !v.integer?
|
109
|
+
warn("Value '#{v}' for option '#{k}' must be integer.")
|
110
|
+
end
|
111
|
+
sanitized[k] = v.ceil
|
112
|
+
else
|
113
|
+
sanitized[k] = v
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
sanitize_timeout!(sanitized, :timeout)
|
118
|
+
sanitize_timeout!(sanitized, :connecttimeout)
|
119
|
+
|
120
|
+
sanitized
|
121
|
+
end
|
122
|
+
|
123
|
+
def sanitize_timeout!(options, timeout)
|
124
|
+
timeout_ms = :"#{timeout}_ms"
|
125
|
+
if options[timeout] && options[timeout].round != options[timeout]
|
126
|
+
if !options[timeout_ms]
|
127
|
+
options[timeout_ms] = (options[timeout]*1000).ceil
|
128
|
+
end
|
129
|
+
options[timeout] = options[timeout].ceil
|
130
|
+
end
|
131
|
+
options
|
132
|
+
end
|
133
|
+
|
134
|
+
# Sets on_complete callback on easy in order to be able to
|
135
|
+
# track progress.
|
136
|
+
#
|
137
|
+
# @example Set callback.
|
138
|
+
# easy_factory.set_callback
|
139
|
+
#
|
140
|
+
# @return [ Ethon::Easy ] The easy.
|
141
|
+
def set_callback
|
142
|
+
if request.streaming?
|
143
|
+
response = nil
|
144
|
+
easy.on_headers do |easy|
|
145
|
+
response = Response.new(Ethon::Easy::Mirror.from_easy(easy).options)
|
146
|
+
request.execute_headers_callbacks(response)
|
147
|
+
end
|
148
|
+
request.on_body.each do |callback|
|
149
|
+
easy.on_body do |chunk, easy|
|
150
|
+
callback.call(chunk, response)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
else
|
154
|
+
easy.on_headers do |easy|
|
155
|
+
request.execute_headers_callbacks(Response.new(Ethon::Easy::Mirror.from_easy(easy).options))
|
156
|
+
end
|
157
|
+
end
|
158
|
+
request.on_progress.each do |callback|
|
159
|
+
easy.on_progress do |dltotal, dlnow, ultotal, ulnow, easy|
|
160
|
+
callback.call(dltotal, dlnow, ultotal, ulnow, response)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
easy.on_complete do |easy|
|
164
|
+
request.finish(Response.new(easy.mirror.options))
|
165
|
+
Typhoeus::Pool.release(easy)
|
166
|
+
if hydra && !hydra.queued_requests.empty?
|
167
|
+
hydra.dequeue_many
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def provide_help(option)
|
173
|
+
if new_option = CHANGED_OPTIONS[option.to_sym]
|
174
|
+
"\nPlease try #{new_option} instead of #{option}." if new_option
|
175
|
+
elsif REMOVED_OPTIONS.include?(option.to_sym)
|
176
|
+
"\nThe option #{option} was removed."
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module Errors
|
3
|
+
|
4
|
+
# Raises when block connection is turned on
|
5
|
+
# and making a real request.
|
6
|
+
class NoStub < TyphoeusError
|
7
|
+
def initialize(request)
|
8
|
+
super("The connection is blocked and no stub defined: #{request.url}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
|
3
|
+
# This class represents an expectation. It is part
|
4
|
+
# of the stubbing mechanism. An expectation contains
|
5
|
+
# a url and options, like a request. They are compared
|
6
|
+
# to the request url and options in order to evaluate
|
7
|
+
# whether they match. If that's the case, the attached
|
8
|
+
# responses are returned one by one.
|
9
|
+
#
|
10
|
+
# @example Stub a request and get specified response.
|
11
|
+
# expected = Typhoeus::Response.new
|
12
|
+
# Typhoeus.stub("www.example.com").and_return(expected)
|
13
|
+
#
|
14
|
+
# actual = Typhoeus.get("www.example.com")
|
15
|
+
# expected == actual
|
16
|
+
# #=> true
|
17
|
+
#
|
18
|
+
# @example Stub a request and get a lazily-constructed response containing data from actual widgets that exist in the system when the stubbed request is made.
|
19
|
+
# Typhoeus.stub("www.example.com/widgets") do
|
20
|
+
# actual_widgets = Widget.all
|
21
|
+
# Typhoeus::Response.new(
|
22
|
+
# :body => actual_widgets.inject([]) do |ids, widget|
|
23
|
+
# ids << widget.id
|
24
|
+
# end.join(",")
|
25
|
+
# )
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @example Stub a request and get a lazily-constructed response in the format requested.
|
29
|
+
# Typhoeus.stub("www.example.com") do |request|
|
30
|
+
# accept = (request.options[:headers]||{})['Accept'] || "application/json"
|
31
|
+
# format = accept.split(",").first
|
32
|
+
# body_obj = { 'things' => [ { 'id' => 'foo' } ] }
|
33
|
+
#
|
34
|
+
# Typhoeus::Response.new(
|
35
|
+
# :headers => {
|
36
|
+
# 'Content-Type' => format
|
37
|
+
# },
|
38
|
+
# :body => SERIALIZERS[format].serialize(body_obj)
|
39
|
+
# )
|
40
|
+
# end
|
41
|
+
class Expectation
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
attr_reader :base_url
|
45
|
+
|
46
|
+
# @api private
|
47
|
+
attr_reader :options
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
attr_reader :from
|
51
|
+
|
52
|
+
class << self
|
53
|
+
|
54
|
+
# Returns all expectations.
|
55
|
+
#
|
56
|
+
# @example Return expectations.
|
57
|
+
# Typhoeus::Expectation.all
|
58
|
+
#
|
59
|
+
# @return [ Array<Typhoeus::Expectation> ] The expectations.
|
60
|
+
def all
|
61
|
+
@expectations ||= []
|
62
|
+
end
|
63
|
+
|
64
|
+
# Clears expectations. This is handy while
|
65
|
+
# testing, and you want to make sure that
|
66
|
+
# you don't get canned responses.
|
67
|
+
#
|
68
|
+
# @example Clear expectations.
|
69
|
+
# Typhoeus::Expectation.clear
|
70
|
+
def clear
|
71
|
+
all.clear
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns stubbed response matching the
|
75
|
+
# provided request.
|
76
|
+
#
|
77
|
+
# @example Find response
|
78
|
+
# Typhoeus::Expectation.response_for(request)
|
79
|
+
#
|
80
|
+
# @return [ Typhoeus::Response ] The stubbed response from a
|
81
|
+
# matching expectation, or nil if no matching expectation
|
82
|
+
# is found.
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
def response_for(request)
|
86
|
+
expectation = find_by(request)
|
87
|
+
return nil if expectation.nil?
|
88
|
+
|
89
|
+
expectation.response(request)
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
def find_by(request)
|
94
|
+
all.find do |expectation|
|
95
|
+
expectation.matches?(request)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Creates an expectation.
|
101
|
+
#
|
102
|
+
# @example Create expectation.
|
103
|
+
# Typhoeus::Expectation.new(base_url)
|
104
|
+
#
|
105
|
+
# @return [ Expectation ] The created expectation.
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
def initialize(base_url, options = {})
|
109
|
+
@base_url = base_url
|
110
|
+
@options = options
|
111
|
+
@response_counter = 0
|
112
|
+
@from = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
# Set from value to mark an expectaion. Useful for
|
116
|
+
# other libraries, e.g. WebMock.
|
117
|
+
#
|
118
|
+
# @example Mark expectation.
|
119
|
+
# expectation.from(:webmock)
|
120
|
+
#
|
121
|
+
# @param [ String ] value Value to set.
|
122
|
+
#
|
123
|
+
# @return [ Expectation ] Returns self.
|
124
|
+
#
|
125
|
+
# @api private
|
126
|
+
def stubbed_from(value)
|
127
|
+
@from = value
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
# Specify what should be returned,
|
132
|
+
# when this expectation is hit.
|
133
|
+
#
|
134
|
+
# @example Add response.
|
135
|
+
# expectation.and_return(response)
|
136
|
+
#
|
137
|
+
# @return [ void ]
|
138
|
+
def and_return(response=nil, &block)
|
139
|
+
new_response = (response.nil? ? block : response)
|
140
|
+
responses.push(*new_response)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Checks whether this expectation matches
|
144
|
+
# the provided request.
|
145
|
+
#
|
146
|
+
# @example Check if request matches.
|
147
|
+
# expectation.matches? request
|
148
|
+
#
|
149
|
+
# @param [ Request ] request The request to check.
|
150
|
+
#
|
151
|
+
# @return [ Boolean ] True when matches, else false.
|
152
|
+
#
|
153
|
+
# @api private
|
154
|
+
def matches?(request)
|
155
|
+
url_match?(request.base_url) && options_match?(request)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Return canned responses.
|
159
|
+
#
|
160
|
+
# @example Return responses.
|
161
|
+
# expectation.responses
|
162
|
+
#
|
163
|
+
# @return [ Array<Typhoeus::Response> ] The responses.
|
164
|
+
#
|
165
|
+
# @api private
|
166
|
+
def responses
|
167
|
+
@responses ||= []
|
168
|
+
end
|
169
|
+
|
170
|
+
# Return the response. When there are
|
171
|
+
# multiple responses, they are returned one
|
172
|
+
# by one.
|
173
|
+
#
|
174
|
+
# @example Return response.
|
175
|
+
# expectation.response
|
176
|
+
#
|
177
|
+
# @return [ Response ] The response.
|
178
|
+
#
|
179
|
+
# @api private
|
180
|
+
def response(request)
|
181
|
+
response = responses.fetch(@response_counter, responses.last)
|
182
|
+
if response.respond_to?(:call)
|
183
|
+
response = response.call(request)
|
184
|
+
end
|
185
|
+
@response_counter += 1
|
186
|
+
response.mock = @from || true
|
187
|
+
response
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
# Check whether the options matches the request options.
|
193
|
+
# I checks options and original options.
|
194
|
+
def options_match?(request)
|
195
|
+
(options ? options.all?{ |k,v| request.original_options[k] == v || request.options[k] == v } : true)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Check whether the base_url matches the request url.
|
199
|
+
# The base_url can be a string, regex or nil. String and
|
200
|
+
# regexp are checked, nil is always true, else false.
|
201
|
+
#
|
202
|
+
# Nil serves as a placeholder in case you want to match
|
203
|
+
# all urls.
|
204
|
+
def url_match?(request_url)
|
205
|
+
case base_url
|
206
|
+
when String
|
207
|
+
base_url == request_url
|
208
|
+
when Regexp
|
209
|
+
base_url === request_url
|
210
|
+
when nil
|
211
|
+
true
|
212
|
+
else
|
213
|
+
false
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
|
4
|
+
# This module handles the request adding on
|
5
|
+
# hydra.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
module Addable
|
9
|
+
|
10
|
+
# Adds request to multi.
|
11
|
+
#
|
12
|
+
# @example Add request.
|
13
|
+
# hydra.add(request)
|
14
|
+
#
|
15
|
+
# @param [ Typhoeus::Request ] request to add.
|
16
|
+
#
|
17
|
+
# @return [ void ]
|
18
|
+
def add(request)
|
19
|
+
multi.add(EasyFactory.new(request, self).get)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
|
4
|
+
# This module provides a way to hook into before
|
5
|
+
# a request gets queued in hydra. This is very powerful
|
6
|
+
# and you should be careful because when you accidently
|
7
|
+
# return a falsy value the request won't be executed.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
module Before
|
11
|
+
|
12
|
+
# Overrride add in order to execute callbacks in
|
13
|
+
# Typhoeus.before. Will break and return when a
|
14
|
+
# callback returns nil, false or a response. Calls super
|
15
|
+
# otherwise.
|
16
|
+
#
|
17
|
+
# @example Add the request.
|
18
|
+
# hydra.add(request)
|
19
|
+
def add(request)
|
20
|
+
Typhoeus.before.each do |callback|
|
21
|
+
value = callback.call(request)
|
22
|
+
if value.nil? || value == false || value.is_a?(Response)
|
23
|
+
dequeue
|
24
|
+
return value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
|
4
|
+
# This module handles the blocked connection request mode on
|
5
|
+
# the hydra side, where only stubbed requests
|
6
|
+
# are allowed.
|
7
|
+
# Connection blocking needs to be turned on:
|
8
|
+
# Typhoeus.configure do |config|
|
9
|
+
# config.block_connection = true
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# When trying to do real requests a NoStub error
|
13
|
+
# is raised.
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
module BlockConnection
|
17
|
+
|
18
|
+
# Overrides add in order to check before if block connection
|
19
|
+
# is turned on. If thats the case a NoStub error is
|
20
|
+
# raised.
|
21
|
+
#
|
22
|
+
# @example Add the request.
|
23
|
+
# hydra.add(request)
|
24
|
+
#
|
25
|
+
# @param [ Request ] request The request to enqueue.
|
26
|
+
def add(request)
|
27
|
+
if request.blocked?
|
28
|
+
raise Typhoeus::Errors::NoStub.new(request)
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
|
4
|
+
# This module handles the GET request memoization
|
5
|
+
# on the hydra side. Memoization needs to be turned
|
6
|
+
# on:
|
7
|
+
# Typhoeus.configure do |config|
|
8
|
+
# config.memoize = true
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
module Memoizable
|
13
|
+
|
14
|
+
# Return the memory.
|
15
|
+
#
|
16
|
+
# @example Return the memory.
|
17
|
+
# hydra.memory
|
18
|
+
#
|
19
|
+
# @return [ Hash ] The memory.
|
20
|
+
def memory
|
21
|
+
@memory ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Overrides add in order to check before if request
|
25
|
+
# is memoizable and already in memory. If thats the case,
|
26
|
+
# super is not called, instead the response is set and
|
27
|
+
# the on_complete callback called.
|
28
|
+
#
|
29
|
+
# @example Add the request.
|
30
|
+
# hydra.add(request)
|
31
|
+
#
|
32
|
+
# @param [ Request ] request The request to add.
|
33
|
+
#
|
34
|
+
# @return [ Request ] The added request.
|
35
|
+
def add(request)
|
36
|
+
if request.memoizable? && memory.has_key?(request)
|
37
|
+
response = memory[request]
|
38
|
+
request.finish(response, true)
|
39
|
+
dequeue
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Overrides run to make sure the memory is cleared after
|
46
|
+
# each run.
|
47
|
+
#
|
48
|
+
# @example Run hydra.
|
49
|
+
# hydra.run
|
50
|
+
def run
|
51
|
+
super
|
52
|
+
memory.clear
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
|
4
|
+
# This module handles the request queueing on
|
5
|
+
# hydra.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
module Queueable
|
9
|
+
|
10
|
+
# Return the queued requests.
|
11
|
+
#
|
12
|
+
# @example Return queued requests.
|
13
|
+
# hydra.queued_requests
|
14
|
+
#
|
15
|
+
# @return [ Array<Typhoeus::Request> ] The queued requests.
|
16
|
+
def queued_requests
|
17
|
+
@queued_requests ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Abort the current hydra run as good as
|
21
|
+
# possible. This means that it only
|
22
|
+
# clears the queued requests and can't do
|
23
|
+
# anything about already running requests.
|
24
|
+
#
|
25
|
+
# @example Abort hydra.
|
26
|
+
# hydra.abort
|
27
|
+
def abort
|
28
|
+
queued_requests.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
# Enqueues a request in order to be performed
|
32
|
+
# by the hydra. This can even be done while
|
33
|
+
# the hydra is running. Also sets hydra on
|
34
|
+
# request.
|
35
|
+
#
|
36
|
+
# @example Queue request.
|
37
|
+
# hydra.queue(request)
|
38
|
+
def queue(request)
|
39
|
+
request.hydra = self
|
40
|
+
queued_requests << request
|
41
|
+
end
|
42
|
+
|
43
|
+
# Pushes a request to the front of the queue,
|
44
|
+
# to be performed by the hydra. Also sets hydra
|
45
|
+
# on request
|
46
|
+
#
|
47
|
+
# @example Queue reques.
|
48
|
+
# hydra.queue_front(request)
|
49
|
+
def queue_front(request)
|
50
|
+
request.hydra = self
|
51
|
+
queued_requests.unshift request
|
52
|
+
end
|
53
|
+
|
54
|
+
# Removes a request from queued_requests and
|
55
|
+
# adds it to the hydra in order to be
|
56
|
+
# performed next.
|
57
|
+
#
|
58
|
+
# @example Dequeue request.
|
59
|
+
# hydra.dequeue
|
60
|
+
#
|
61
|
+
# @since 0.6.4
|
62
|
+
def dequeue
|
63
|
+
add(queued_requests.shift) unless queued_requests.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Removes requests from queued_requests and
|
67
|
+
# adds them to the hydra until max_concurrency
|
68
|
+
# is reached.
|
69
|
+
#
|
70
|
+
# @example Dequeue requests.
|
71
|
+
# hydra.dequeue_many
|
72
|
+
#
|
73
|
+
# @since 0.6.8
|
74
|
+
def dequeue_many
|
75
|
+
number = multi.easy_handles.count
|
76
|
+
until number == max_concurrency || queued_requests.empty?
|
77
|
+
add(queued_requests.shift)
|
78
|
+
number += 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
|
4
|
+
# This module contains logic to run a hydra.
|
5
|
+
module Runnable
|
6
|
+
|
7
|
+
# Start the hydra run.
|
8
|
+
#
|
9
|
+
# @example Start hydra run.
|
10
|
+
# hydra.run
|
11
|
+
#
|
12
|
+
# @return [ Symbol ] Return value from multi.perform.
|
13
|
+
def run
|
14
|
+
dequeue_many
|
15
|
+
multi.perform
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|