faraday-typhoeus 0.1.0
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 +7 -0
- data/LICENSE.md +21 -0
- data/README.md +147 -0
- data/lib/faraday/adapter/typhoeus.rb +187 -0
- data/lib/faraday/typhoeus/version.rb +7 -0
- data/lib/faraday/typhoeus.rb +14 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 93cb5577c71cc18d04be6150ccf60886529527a21b06ce229a49da67f047df98
|
4
|
+
data.tar.gz: 2210f5945cb6873e7a3e0f751355a4da96b4d2b60ced5d3e40fc1aa0a3f085d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3a1bb851c5f5bbf84176fe4f63e57480bfc35af59a90961aa1b4b2084a0adeb06f8453340c19aeb21b77690a0a255083eb82f3b23874248a03d8be6232667e2a
|
7
|
+
data.tar.gz: 688e444af7f0222bf5d4e1bdf04133884a565b9a507d1f600fe936915921accb9da563eb836b214b8ddf228de609405aa7094c8a47418a7fe67b3464fff3e117
|
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Jan van der Pas
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# Faraday Typhoeus Adapter
|
2
|
+
|
3
|
+
This is a [Faraday][faraday] adapter for the [Typhoeus][typhoeus] parallel HTTP client. It supports parallel HTTP requests and streaming.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'faraday-typhoeus'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install faraday-typhoeus
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Basic
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
conn = Faraday.new(...) do |f|
|
27
|
+
f.adapter :typhoeus
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
### Typhoeus Options
|
32
|
+
|
33
|
+
You can also include options for [Typhoeus][typhoeus_options]/[Ethon][ethon_options] that will be used in every request:
|
34
|
+
|
35
|
+
Note that block-style configuration for the adapter is not currently supported.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
conn = Faraday.new(...) do |f|
|
39
|
+
f.adapter :typhoeus, forbid_reuse: true, maxredirs: 1
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
### Parallel Requests
|
44
|
+
|
45
|
+
The adapter supports Typhoeus's parallel request functionality:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
conn = Faraday.new(...) do |f|
|
49
|
+
f.request :url_encoded
|
50
|
+
f.response :logger
|
51
|
+
f.adapter :typhoeus
|
52
|
+
end
|
53
|
+
|
54
|
+
responses = []
|
55
|
+
|
56
|
+
conn.in_parallel do
|
57
|
+
# responses[0].body will be null here since the requests have not been
|
58
|
+
# completed
|
59
|
+
responses = [
|
60
|
+
conn.get('/first'),
|
61
|
+
conn.get('/second'),
|
62
|
+
]
|
63
|
+
end
|
64
|
+
|
65
|
+
# after it has been completed the response information is fully available in
|
66
|
+
# response[0].status, etc
|
67
|
+
responses[0].body
|
68
|
+
responses[1].body
|
69
|
+
```
|
70
|
+
|
71
|
+
### Streaming Responses
|
72
|
+
|
73
|
+
The adapter supports [streamed responses](faraday_streaming) via the `on_data` option:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
conn = Faraday.new(...) do |f|
|
77
|
+
f.adapter :typhoeus
|
78
|
+
end
|
79
|
+
|
80
|
+
# Streaming
|
81
|
+
|
82
|
+
chunks = []
|
83
|
+
|
84
|
+
conn.get('/stream') do |req|
|
85
|
+
req.options.on_data proc do |chunk, received_bytes|
|
86
|
+
chunks << chunk
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
body = chunks.join
|
91
|
+
|
92
|
+
# Server-Sent Event Polling
|
93
|
+
|
94
|
+
body = nil
|
95
|
+
|
96
|
+
begin
|
97
|
+
conn.get('/events') do |req|
|
98
|
+
req.options.timeout = 30
|
99
|
+
|
100
|
+
req.options.on_data = proc do |chunk|
|
101
|
+
# stop listening once we get some data (YMMV)
|
102
|
+
if chunk.start_with?('data: ')
|
103
|
+
body = chunk
|
104
|
+
:abort # abort the request, we're done
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue Faraday::ConnectionFailed => ex
|
109
|
+
raise ex unless body
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
## Resources
|
114
|
+
|
115
|
+
- See [Typhoeus Documentation][typhoeus] for more info.
|
116
|
+
|
117
|
+
## Development
|
118
|
+
|
119
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
120
|
+
|
121
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](rubygems).
|
122
|
+
|
123
|
+
### TODO
|
124
|
+
|
125
|
+
- [ ] Better tests for parallel functionality (can port them over from Typhoeus)
|
126
|
+
- [ ] Support block-based configuration like other adapters
|
127
|
+
- [ ] Refactor the adapter a bit to look more like other Faraday 2 adapters (use `connection` etc.)
|
128
|
+
- [ ] Compression support
|
129
|
+
- [ ] Reason-phrase parsing support
|
130
|
+
|
131
|
+
## Contributing
|
132
|
+
|
133
|
+
Bug reports and pull requests are welcome on [GitHub][repo].
|
134
|
+
|
135
|
+
## License
|
136
|
+
|
137
|
+
The gem is available as open source under the terms of the [license][license].
|
138
|
+
|
139
|
+
|
140
|
+
[faraday]: https://github.com/lostisland/faraday
|
141
|
+
[typhoeus]: https://github.com/typhoeus/typhoeus
|
142
|
+
[typhoeus_options]: https://github.com/typhoeus/typhoeus/blob/3544111b76b95d13da7cc6bfe4eb07921d771d93/lib/typhoeus/easy_factory.rb#L13-L39
|
143
|
+
[ethon_options]: https://github.com/typhoeus/ethon/blob/5d9ddf8f609a6be4b5c60d55e1e338eeeb08f25f/lib/ethon/curls/options.rb#L214-L499
|
144
|
+
[faraday_streaming]: https://lostisland.github.io/faraday/usage/streaming
|
145
|
+
[repo]: https://github.com/dleavitt/faraday-typhoeus
|
146
|
+
[license]: LICENSE.md
|
147
|
+
[rubygems]: https://github.com/dleavitt/faraday-typhoeus/blob/main/rubygems
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'typhoeus'
|
4
|
+
|
5
|
+
module Faraday
|
6
|
+
class Adapter
|
7
|
+
# This class provides the main implementation for your adapter.
|
8
|
+
# There are some key responsibilities that your adapter should satisfy:
|
9
|
+
# * Initialize and store internally the client you chose (e.g. Net::HTTP)
|
10
|
+
# * Process requests and save the response (see `#call`)
|
11
|
+
class Typhoeus < Faraday::Adapter
|
12
|
+
self.supports_parallel = true
|
13
|
+
|
14
|
+
# The initialize method is lazy-called ONCE when the connection stack is
|
15
|
+
# built. See https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb
|
16
|
+
#
|
17
|
+
# @param app [#call] the "rack app" wrapped in middleware. See
|
18
|
+
# https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb#L157
|
19
|
+
# @param opts [Hash] the options hash with all the options necessary for
|
20
|
+
# the adapter to correctly configure itself. These are automatically
|
21
|
+
# stored into `@connection_options` when you call `super`.
|
22
|
+
def initialize(app = nil, opts = {}, &block)
|
23
|
+
super(app, opts, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Setup Hydra with provided options.
|
27
|
+
#
|
28
|
+
# @example Setup Hydra.
|
29
|
+
# Faraday::Adapter::Typhoeus.setup_parallel_manager
|
30
|
+
# #=> #<Typhoeus::Hydra ... >
|
31
|
+
#
|
32
|
+
# @param (see Typhoeus::Hydra#initialize)
|
33
|
+
# @option (see Typhoeus::Hydra#initialize)
|
34
|
+
#
|
35
|
+
# @return [ Typhoeus::Hydra ] The hydra.
|
36
|
+
def self.setup_parallel_manager(options = {})
|
37
|
+
::Typhoeus::Hydra.new(options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param env [Faraday::Env] the environment of the request being processed
|
41
|
+
def call(env)
|
42
|
+
super
|
43
|
+
perform_request env
|
44
|
+
@app.call(env)
|
45
|
+
|
46
|
+
# NOTE: An adapter `call` MUST return the `env.response`. If
|
47
|
+
# `save_response` is the last line in your `call` method implementation,
|
48
|
+
# it will automatically return the response for you. Otherwise, you'll
|
49
|
+
# need to manually do so. You can do this with any (not both) of the
|
50
|
+
# following lines:
|
51
|
+
# * @app.call(env)
|
52
|
+
# * env.response
|
53
|
+
#
|
54
|
+
# Finally, it's good practice to rescue client-specific exceptions (e.g.
|
55
|
+
# Timeout, ConnectionFailed, etc...) and re-raise them as Faraday
|
56
|
+
# Errors. Check `Faraday::Error` for a list of all errors.
|
57
|
+
#
|
58
|
+
# rescue MyAdapterTimeout => e
|
59
|
+
# # Most errors allow you to provide the original exception and optionally (if available) the response, to
|
60
|
+
# # make them available outside of the middleware stack.
|
61
|
+
# raise Faraday::TimeoutError, e
|
62
|
+
# end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def perform_request(env)
|
68
|
+
if parallel?(env)
|
69
|
+
env[:parallel_manager].queue request(env)
|
70
|
+
else
|
71
|
+
request(env).run
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def request(env)
|
76
|
+
read_body env
|
77
|
+
|
78
|
+
req = typhoeus_request(env)
|
79
|
+
|
80
|
+
configure_ssl req, env
|
81
|
+
configure_proxy req, env
|
82
|
+
configure_timeout req, env
|
83
|
+
configure_socket req, env
|
84
|
+
|
85
|
+
if env[:request][:on_data].is_a?(Proc)
|
86
|
+
yielded = false
|
87
|
+
size = 0
|
88
|
+
|
89
|
+
req.on_body do |chunk|
|
90
|
+
if chunk.bytesize.positive? || size.positive?
|
91
|
+
yielded = true
|
92
|
+
size += chunk.bytesize
|
93
|
+
|
94
|
+
env[:request][:on_data].call(chunk, size)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
req.on_complete do |_resp|
|
99
|
+
env[:request][:on_data].call(+'', 0) unless yielded
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
req.on_complete do |resp|
|
104
|
+
if resp.timed_out?
|
105
|
+
env[:typhoeus_timed_out] = true
|
106
|
+
unless parallel?(env)
|
107
|
+
raise Faraday::TimeoutError, 'request timed out'
|
108
|
+
end
|
109
|
+
elsif resp.response_code.zero? || ((resp.return_code != :ok) && !resp.mock?)
|
110
|
+
env[:typhoeus_connection_failed] = true
|
111
|
+
env[:typhoeus_return_message] = resp.return_message
|
112
|
+
unless parallel?(env)
|
113
|
+
raise Faraday::ConnectionFailed, resp.return_message
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
save_response(env, resp.code, resp.body) do |response_headers|
|
118
|
+
response_headers.parse resp.response_headers
|
119
|
+
end
|
120
|
+
# in async mode, :response is initialized at this point
|
121
|
+
env[:response].finish(env) if parallel?(env)
|
122
|
+
end
|
123
|
+
|
124
|
+
req
|
125
|
+
end
|
126
|
+
|
127
|
+
def typhoeus_request(env)
|
128
|
+
opts = {
|
129
|
+
method: env[:method],
|
130
|
+
body: env[:body],
|
131
|
+
headers: env[:request_headers]
|
132
|
+
}.merge(@connection_options)
|
133
|
+
|
134
|
+
::Typhoeus::Request.new(env[:url].to_s, opts)
|
135
|
+
end
|
136
|
+
|
137
|
+
def read_body(env)
|
138
|
+
env[:body] = env[:body].read if env[:body].respond_to? :read
|
139
|
+
end
|
140
|
+
|
141
|
+
def configure_ssl(req, env)
|
142
|
+
ssl = env[:ssl]
|
143
|
+
|
144
|
+
verify_p = ssl&.fetch(:verify, true)
|
145
|
+
|
146
|
+
ssl_verifyhost = verify_p ? 2 : 0
|
147
|
+
req.options[:ssl_verifyhost] = ssl_verifyhost
|
148
|
+
req.options[:ssl_verifypeer] = verify_p
|
149
|
+
req.options[:sslversion] = ssl[:version] if ssl[:version]
|
150
|
+
req.options[:sslcert] = ssl[:client_cert] if ssl[:client_cert]
|
151
|
+
req.options[:sslkey] = ssl[:client_key] if ssl[:client_key]
|
152
|
+
req.options[:cainfo] = ssl[:ca_file] if ssl[:ca_file]
|
153
|
+
req.options[:capath] = ssl[:ca_path] if ssl[:ca_path]
|
154
|
+
client_cert_passwd_key = %i[client_cert_passwd client_certificate_password].detect { |name| ssl.key?(name) }
|
155
|
+
req.options[:keypasswd] = ssl[client_cert_passwd_key] if client_cert_passwd_key
|
156
|
+
end
|
157
|
+
|
158
|
+
def configure_proxy(req, env)
|
159
|
+
proxy = env[:request][:proxy]
|
160
|
+
return unless proxy
|
161
|
+
|
162
|
+
req.options[:proxy] = "#{proxy[:uri].scheme}://#{proxy[:uri].host}:#{proxy[:uri].port}"
|
163
|
+
|
164
|
+
if proxy[:user] && proxy[:password]
|
165
|
+
req.options[:proxyauth] = :any
|
166
|
+
req.options[:proxyuserpwd] = "#{proxy[:user]}:#{proxy[:password]}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def configure_timeout(req, env)
|
171
|
+
env_req = env[:request]
|
172
|
+
req.options[:timeout_ms] = (env_req[:timeout] * 1000).to_i if env_req[:timeout]
|
173
|
+
req.options[:connecttimeout_ms] = (env_req[:open_timeout] * 1000).to_i if env_req[:open_timeout]
|
174
|
+
end
|
175
|
+
|
176
|
+
def configure_socket(req, env)
|
177
|
+
if (bind = env[:request][:bind])
|
178
|
+
req.options[:interface] = bind[:host]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def parallel?(env)
|
183
|
+
!!env[:parallel_manager]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'adapter/typhoeus'
|
4
|
+
require_relative 'typhoeus/version'
|
5
|
+
|
6
|
+
module Faraday
|
7
|
+
# Main Faraday::Typhoeus adapter namespace
|
8
|
+
module Typhoeus
|
9
|
+
# Register adapter so either of the following work
|
10
|
+
# * conn.adapter Faraday::Adapter::Typhoeus
|
11
|
+
# * conn.adapter :typhoeus
|
12
|
+
Faraday::Adapter.register_middleware(typhoeus: Faraday::Adapter::Typhoeus)
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: faraday-typhoeus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Leavitt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-04-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: typhoeus
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.4'
|
41
|
+
description: Faraday adapter for Typhoeus
|
42
|
+
email:
|
43
|
+
- daniel.leavitt@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE.md
|
49
|
+
- README.md
|
50
|
+
- lib/faraday/adapter/typhoeus.rb
|
51
|
+
- lib/faraday/typhoeus.rb
|
52
|
+
- lib/faraday/typhoeus/version.rb
|
53
|
+
homepage: https://github.com/dleavitt/faraday-typhoeus
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata:
|
57
|
+
homepage_uri: https://github.com/dleavitt/faraday-typhoeus
|
58
|
+
source_code_uri: https://github.com/dleavitt/faraday-typhoeus
|
59
|
+
changelog_uri: https://github.com/dleavitt/faraday-typhoeus
|
60
|
+
rubygems_mfa_required: 'true'
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.7.0
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubygems_version: 3.3.7
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: Faraday adapter for Typhoeus
|
80
|
+
test_files: []
|