async-http 0.50.7 → 0.50.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e2b32bb7262cafc68c516d881d6f3a551597248b06b627ae150111dcfa2b656
4
- data.tar.gz: 63f025a564598ec263413f70b9f4a9561a52d1ebbde4d1b2e66c4c9a5a461b89
3
+ metadata.gz: 6140b4806e8fff4a017e4d2973e2d6ecd28bc248069774d351b13fc5ea907ecf
4
+ data.tar.gz: 9eef40decca9b155053f7419993d705e280d0ea51e385dc030efebe6d20d4933
5
5
  SHA512:
6
- metadata.gz: a2d4dad8cdbf23281345f4ab8e5d7d0b58f83f86513940aa108ba292b82defd2ab5bb23b8fd117618ecc0be1a7ecc1d74a81f65582be18362c5bd7d82072f26f
7
- data.tar.gz: bef0076a4130b928e1ffd7f42abf15647d639b6ee125de1f71f50d50ae6ede8631f0e11b8c85b455916f3e5417113907de93a9d69e79ac281804d121480c587b
6
+ metadata.gz: dc926ac38b9d1bf6860ff23282f9c90eb78b965c881fae8130501e0cb4260c757bcf9bb8ee634674b2c3a37b013496ae08a332e54309e0f90979779197505d2c
7
+ data.tar.gz: b1fb1c1cbbea6b31bdeccaec48972bff12b58f86c8d6b1e5d42f36e389d3c7d5040839d8a74359cc835002e15631bc754a168d8ae643814bfe71e1ea0eadbc7d
data/.travis.yml CHANGED
@@ -11,6 +11,8 @@ addons:
11
11
  packages:
12
12
  - wrk
13
13
 
14
+ script: bundle exec rspec
15
+
14
16
  matrix:
15
17
  include:
16
18
  - rvm: 2.4
data/README.md CHANGED
@@ -160,9 +160,9 @@ Here is a basic example of a client/server running in the same reactor:
160
160
  ```ruby
161
161
  #!/usr/bin/env ruby
162
162
 
163
+ require 'async'
163
164
  require 'async/http/server'
164
165
  require 'async/http/client'
165
- require 'async/reactor'
166
166
  require 'async/http/endpoint'
167
167
  require 'async/http/protocol/response'
168
168
 
@@ -175,7 +175,7 @@ end
175
175
  server = Async::HTTP::Server.new(app, endpoint)
176
176
  client = Async::HTTP::Client.new(endpoint)
177
177
 
178
- Async::Reactor.run do |task|
178
+ Async do |task|
179
179
  server_task = task.async do
180
180
  server.run
181
181
  end
data/async-http.gemspec CHANGED
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  # spec.add_dependency("openssl")
29
29
 
30
+ spec.add_development_dependency "bake-bundler"
31
+
30
32
  spec.add_development_dependency "async-rspec", "~> 1.10"
31
33
  spec.add_development_dependency "async-container", "~> 0.14.0"
32
34
 
@@ -36,5 +38,4 @@ Gem::Specification.new do |spec|
36
38
  spec.add_development_dependency "covered"
37
39
  spec.add_development_dependency "bundler"
38
40
  spec.add_development_dependency "rspec", "~> 3.6"
39
- spec.add_development_dependency "rake"
40
41
  end
data/bake/async/http.rb CHANGED
@@ -21,7 +21,7 @@ def fetch(url, method:)
21
21
  format_body = proc do |body, terminal|
22
22
  if body
23
23
  if length = body.length
24
- terminal.print(:body, "body with length", :length, length, "B")
24
+ terminal.print(:body, "body with length ", :length, length, "B")
25
25
  else
26
26
  terminal.print(:body, "body without length")
27
27
  end
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async'
4
+ require 'async/clock'
5
+ require 'async/barrier'
6
+ require_relative '../../lib/async/http/endpoint'
7
+ require_relative '../../lib/async/http/client'
8
+
9
+ Async do
10
+ url = "https://static.openfoodfacts.org/data/en.openfoodfacts.org.products.csv"
11
+
12
+ endpoint = Async::HTTP::Endpoint.parse(url)
13
+ client = Async::HTTP::Client.new(endpoint)
14
+
15
+ headers = {'user-agent' => 'curl/7.69.1', 'accept' => '*/*'}
16
+
17
+ file = File.open("products.csv", "w")
18
+ Async.logger.info(self) {"Saving download to #{Dir.pwd}"}
19
+
20
+ begin
21
+ response = client.head(endpoint.path, headers)
22
+ content_length = nil
23
+
24
+ if response.success?
25
+ unless response.headers['accept-ranges'].include?('bytes')
26
+ raise "Does not advertise support for accept-ranges: bytes!"
27
+ end
28
+
29
+ unless content_length = response.body&.length
30
+ raise "Could not determine length of response!"
31
+ end
32
+ end
33
+ ensure
34
+ response&.close
35
+ end
36
+
37
+ Async.logger.info(self) {"Content length: #{content_length/(1024**2)}MiB"}
38
+
39
+ parts = []
40
+ offset = 0
41
+ chunk_size = 1024*1024
42
+
43
+ start_time = Async::Clock.now
44
+ amount = 0
45
+
46
+ while offset < content_length
47
+ byte_range_start = offset
48
+ byte_range_end = [offset + chunk_size, content_length].min
49
+ parts << (byte_range_start...byte_range_end)
50
+
51
+ offset += chunk_size
52
+ end
53
+
54
+ Async.logger.info(self) {"Breaking download into #{parts.size} parts..."}
55
+
56
+ barrier = Async::Barrier.new
57
+
58
+ while !parts.empty?
59
+ barrier.async do
60
+ part = parts.shift
61
+
62
+ Async.logger.info(self) {"Issuing range request range: bytes=#{part.min}-#{part.max}"}
63
+
64
+ response = client.get(endpoint.path, [
65
+ ["range", "bytes=#{part.min}-#{part.max-1}"],
66
+ *headers
67
+ ])
68
+
69
+ if response.success?
70
+ Async.logger.info(self) {"Got response: #{response}... writing data for #{part}."}
71
+ written = file.pwrite(response.read, part.min)
72
+
73
+ amount += written
74
+
75
+ duration = Async::Clock.now - start_time
76
+ Async.logger.info(self) {"Rate: #{((amount.to_f/(1024**2))/duration).round(2)}MiB/s"}
77
+ end
78
+ end
79
+ end
80
+
81
+ barrier.wait
82
+ ensure
83
+ client&.close
84
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async'
4
+ require 'async/http/internet'
5
+
6
+ Async do |parent|
7
+ internet = Async::HTTP::Internet.new
8
+ connection = nil
9
+
10
+ child = parent.async do
11
+ response = internet.get("https://utopia-falcon-heroku.herokuapp.com/beer/index")
12
+ connection = response.connection
13
+
14
+ response.each do |chunk|
15
+ Async.logger.info(response) {chunk}
16
+ end
17
+ ensure
18
+ Async.logger.info(response) {"Closing response..."}
19
+ response&.close
20
+ end
21
+
22
+ parent.sleep(5)
23
+
24
+ Async.logger.info(parent) {"Killing #{child}..."}
25
+ child.stop
26
+ ensure
27
+ internet&.close
28
+ end
@@ -103,36 +103,53 @@ module Async
103
103
  # As we cache pool, it's possible these pool go bad (e.g. closed by remote host). In this case, we need to try again. It's up to the caller to impose a timeout on this. If this is the last attempt, we force a new connection.
104
104
  connection = @pool.acquire
105
105
 
106
- response = request.call(connection)
106
+ response = make_response(request, connection)
107
107
 
108
- # The connection won't be released until the body is completely read/released.
109
- ::Protocol::HTTP::Body::Streamable.wrap(response) do
110
- @pool.release(connection)
111
- end
108
+ # This signals that the ensure block below should not try to release the connection, because it's bound into the response which will be returned:
109
+ connection = nil
112
110
 
113
111
  return response
114
112
  rescue Protocol::RequestFailed
115
113
  # This is a specific case where the entire request wasn't sent before a failure occurred. So, we can even resend non-idempotent requests.
116
- @pool.release(connection) if connection
114
+ if connection
115
+ @pool.release(connection)
116
+ connection = nil
117
+ end
117
118
 
118
119
  if attempt < @retries
119
120
  retry
120
121
  else
121
122
  raise
122
123
  end
123
- rescue
124
- @pool.release(connection) if connection
124
+ rescue Errno::ECONNRESET, Errno::EPIPE, IOError
125
+ if connection
126
+ @pool.release(connection)
127
+ connection = nil
128
+ end
125
129
 
126
130
  if request.idempotent? and attempt < @retries
127
131
  retry
128
132
  else
129
133
  raise
130
134
  end
135
+ ensure
136
+ @pool.release(connection) if connection
131
137
  end
132
138
  end
133
139
 
134
140
  protected
135
141
 
142
+ def make_response(request, connection)
143
+ response = request.call(connection)
144
+
145
+ # The connection won't be released until the body is completely read/released.
146
+ ::Protocol::HTTP::Body::Streamable.wrap(response) do
147
+ @pool.release(connection)
148
+ end
149
+
150
+ return response
151
+ end
152
+
136
153
  def make_pool(connection_limit)
137
154
  Async::Pool::Controller.wrap(limit: connection_limit) do
138
155
  Async.logger.debug(self) {"Making connection to #{@endpoint.inspect}"}
@@ -22,6 +22,6 @@
22
22
 
23
23
  module Async
24
24
  module HTTP
25
- VERSION = "0.50.7"
25
+ VERSION = "0.50.8"
26
26
  end
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.50.7
4
+ version: 0.50.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-21 00:00:00.000000000 Z
11
+ date: 2020-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.11.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: bake-bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: async-rspec
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -192,20 +206,6 @@ dependencies:
192
206
  - - "~>"
193
207
  - !ruby/object:Gem::Version
194
208
  version: '3.6'
195
- - !ruby/object:Gem::Dependency
196
- name: rake
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - ">="
200
- - !ruby/object:Gem::Version
201
- version: '0'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - ">="
207
- - !ruby/object:Gem::Version
208
- version: '0'
209
209
  description:
210
210
  email:
211
211
  - samuel.williams@oriontransfer.co.nz
@@ -219,13 +219,13 @@ files:
219
219
  - ".travis.yml"
220
220
  - Gemfile
221
221
  - README.md
222
- - Rakefile
223
222
  - async-http.gemspec
224
223
  - bake.rb
225
224
  - bake/async/http.rb
226
225
  - bake/async/http/h2spec.rb
227
226
  - examples/compare/Gemfile
228
227
  - examples/compare/benchmark.rb
228
+ - examples/download/chunked.rb
229
229
  - examples/fetch/Gemfile
230
230
  - examples/fetch/Gemfile.lock
231
231
  - examples/fetch/README.md
@@ -234,6 +234,7 @@ files:
234
234
  - examples/fetch/public/stream.js
235
235
  - examples/google/search.rb
236
236
  - examples/request.rb
237
+ - examples/stream/stop.rb
237
238
  - examples/trenni/Gemfile
238
239
  - examples/trenni/streaming.rb
239
240
  - examples/upload/client.rb
data/Rakefile DELETED
@@ -1,9 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new
5
-
6
- task :default => :spec
7
-
8
- # Load all rake tasks:
9
- import(*Dir.glob('tasks/**/*.rake'))