async-http 0.31.1 → 0.32.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20c4728c088a68663d0f336b2326d3e988a342c5d1f1cd2890a12e43cefda133
4
- data.tar.gz: da0503f98a16003b0a2c6606e4419ebb311365dac4be7ea685b18bb994b3613c
3
+ metadata.gz: a35d727fb4d1811ad0ddea60170aef62f60084759c1c2d0f658e335f3496be4d
4
+ data.tar.gz: 58004aea432052f2979346a359ad55f2d098f9fa1d9f03e4f89bd08474ced951
5
5
  SHA512:
6
- metadata.gz: 5ecdd9b68abcaf50db65f02ab8f1db4e8ce1e4a00af980510df5d1323a0d4c3b2c135d85fe3683dcf02f5e818b364fe659c44ab5df25459b687ba2a50d8db9e2
7
- data.tar.gz: 68536e0f1ea03914f0e4b34116e7a7f738c5fbc7cf2baf9f2d87f7dd6675329c6c48b444ece69cf8a977f4184a525df1fc14b25bb3f7cb3a85c4983519551eed
6
+ metadata.gz: cee0898153224018a6d9a6b04b5da0635895c59aeb3f37fe5ee3fa20260529a887ee73398afa34ec98ab443a5699d0506bf40fab54123705c1f336ff7e381d72
7
+ data.tar.gz: fb39c47f2edb32732b16d8a8ac3cd8158f6f78212d4dae6af2201eedc24b6bdf30085a1670b4040fb23f384b51efdf9fcaa4b09994a25c86004da9672a4104e2
@@ -20,3 +20,20 @@
20
20
 
21
21
  require_relative 'body/writable'
22
22
  require_relative 'body/buffered'
23
+
24
+ module Async
25
+ module HTTP
26
+ # These classes implement a general IO model for streaming HTTP bodies.
27
+ module Body
28
+ # The implementation assumes a sequential unbuffered stream of data.
29
+ # class Body
30
+ # def each -> yield(String | nil)
31
+ # def read -> String | nil
32
+ # def join -> String
33
+
34
+ # def finish -> buffer the stream and close it.
35
+ # def close(error = nil) -> close the stream immediately.
36
+ # end
37
+ end
38
+ end
39
+ end
@@ -54,6 +54,10 @@ module Async
54
54
  @index = 0
55
55
  end
56
56
 
57
+ def finish
58
+ self
59
+ end
60
+
57
61
  def length
58
62
  @length ||= @chunks.inject(0) {|sum, chunk| sum + chunk.bytesize}
59
63
  end
@@ -62,10 +66,6 @@ module Async
62
66
  @index >= @chunks.length
63
67
  end
64
68
 
65
- def close
66
- self
67
- end
68
-
69
69
  def read
70
70
  if chunk = @chunks[@index]
71
71
  @index += 1
@@ -36,9 +36,14 @@ module Async
36
36
  @finished
37
37
  end
38
38
 
39
- def stop(error)
40
- @protocol.close
41
- @finished = true
39
+ def close(error = nil)
40
+ # We only close the connection if we haven't completed reading the entire body:
41
+ unless @finished
42
+ @protocol.close
43
+ @finished = true
44
+ end
45
+
46
+ super
42
47
  end
43
48
 
44
49
  def read
@@ -55,6 +55,12 @@ module Async
55
55
  @output_length = 0
56
56
  end
57
57
 
58
+ def close(error = nil)
59
+ @stream.close unless @stream.closed?
60
+
61
+ super
62
+ end
63
+
58
64
  def length
59
65
  # We don't know the length of the output until after it's been compressed.
60
66
  nil
@@ -71,13 +77,6 @@ module Async
71
77
  end
72
78
  end
73
79
 
74
- def stop(error)
75
- # There are two ways for the stream to be closed. Either #read returns nil or #stop is called.
76
- @stream.close unless @stream.closed?
77
-
78
- super
79
- end
80
-
81
80
  def inspect
82
81
  "#{super} | \#<#{self.class} #{(ratio*100).round(2)}%>"
83
82
  end
@@ -46,6 +46,13 @@ module Async
46
46
  end
47
47
  end
48
48
 
49
+ def close(error = nil)
50
+ @file.close
51
+ @remaining = 0
52
+
53
+ super
54
+ end
55
+
49
56
  attr :offset
50
57
  attr :length
51
58
 
@@ -57,11 +64,6 @@ module Async
57
64
  @file.seek(@offset)
58
65
  end
59
66
 
60
- def close
61
- @file.close
62
- @remaining = 0
63
- end
64
-
65
67
  def read
66
68
  if @remaining > 0
67
69
  amount = [@remaining, @block_size].min
@@ -70,8 +72,6 @@ module Async
70
72
  @remaining -= chunk.bytesize
71
73
 
72
74
  return chunk
73
- else
74
- @file.close
75
75
  end
76
76
  end
77
77
  end
@@ -37,10 +37,12 @@ module Async
37
37
  @remaining == 0
38
38
  end
39
39
 
40
- def stop(error)
40
+ def close(error = nil)
41
41
  if @remaining != 0
42
42
  @stream.close
43
43
  end
44
+
45
+ super
44
46
  end
45
47
 
46
48
  def read
@@ -75,9 +77,11 @@ module Async
75
77
  @stream.closed?
76
78
  end
77
79
 
78
- def stop(error)
80
+ def close(error = nil)
79
81
  # We can't really do anything in this case except close the connection.
80
82
  @stream.close
83
+
84
+ super
81
85
  end
82
86
 
83
87
  def read
@@ -25,9 +25,17 @@ module Async
25
25
  module Body
26
26
  # A generic base class for wrapping body instances. Typically you'd override `#read`.
27
27
  class Readable
28
- # Read all remaining chunks into a buffered body.
29
- def close
30
- Buffered.for(self)
28
+ # Read all remaining chunks into a buffered body and close the underlying input.
29
+ def finish
30
+ buffered = Buffered.for(self)
31
+
32
+ self.close
33
+
34
+ return buffered
35
+ end
36
+
37
+ # The consumer can call stop to signal that the stream output has terminated.
38
+ def close(error = nil)
31
39
  end
32
40
 
33
41
  # Will read return any data?
@@ -44,11 +52,7 @@ module Async
44
52
  nil
45
53
  end
46
54
 
47
- # The consumer can call stop to signal that the stream output has terminated.
48
- def stop(error)
49
- end
50
-
51
- # Enumerate all chunks until finished. If an error is thrown, #stop will be invoked.
55
+ # Enumerate all chunks until finished. Then invoke `#close`.
52
56
  def each
53
57
  return to_enum unless block_given?
54
58
 
@@ -56,10 +60,8 @@ module Async
56
60
  yield chunk
57
61
  # chunk.clear
58
62
  end
59
- rescue
60
- stop($!)
61
-
62
- raise
63
+ ensure
64
+ self.close($!)
63
65
  end
64
66
 
65
67
  # Read all remaining chunks into a single binary string.
@@ -34,24 +34,19 @@ module Async
34
34
  end
35
35
  end
36
36
 
37
- # Immediately stop reading the body. May close the underlying connection. Discards body.
38
- def stop(error = EOFError)
39
- if self.body
40
- self.body.stop(error)
41
- self.body = nil
42
- end
43
- end
44
-
45
37
  # Gracefully finish reading the body. This will buffer the remainder of the body.
46
38
  def finish
47
39
  if self.body
48
- self.body = self.body.close
40
+ self.body = self.body.finish
49
41
  end
50
42
  end
51
43
 
52
- # Close the connection as quickly as possible. Discards body.
53
- def close
54
- self.stop
44
+ # Close the connection as quickly as possible. Discards body. May close the underlying connection if necessary to terminate the stream.
45
+ def close(error = nil)
46
+ if self.body
47
+ self.body.close(error)
48
+ self.body = nil
49
+ end
55
50
  end
56
51
 
57
52
  # Whether there is a body?
@@ -23,7 +23,7 @@ require_relative 'wrapper'
23
23
  module Async
24
24
  module HTTP
25
25
  module Body
26
- # A body which buffers all it's contents.
26
+ # A body which buffers all it's contents as it is `#read`.
27
27
  class Rewindable < Wrapper
28
28
  def initialize(body)
29
29
  super(body)
@@ -44,7 +44,7 @@ module Async
44
44
  @remaining = remaining
45
45
  end
46
46
 
47
- def stop(*)
47
+ def close(*)
48
48
  super
49
49
 
50
50
  @callback.call
@@ -29,6 +29,20 @@ module Async
29
29
  @body = body
30
30
  end
31
31
 
32
+ # The wrapped body.
33
+ attr :body
34
+
35
+ # Buffer any remaining body.
36
+ def finish
37
+ @body.finish
38
+ end
39
+
40
+ def close(error = nil)
41
+ @body.close(error)
42
+
43
+ super
44
+ end
45
+
32
46
  def empty?
33
47
  @body.empty?
34
48
  end
@@ -37,22 +51,11 @@ module Async
37
51
  @body.length
38
52
  end
39
53
 
40
- # Buffer any remaining body.
41
- def close
42
- @body = @body.close
43
-
44
- return self
45
- end
46
-
47
54
  # Read the next available chunk.
48
55
  def read
49
56
  @body.read
50
57
  end
51
58
 
52
- def stop(error)
53
- @body.stop(error)
54
- end
55
-
56
59
  def inspect
57
60
  return @body.inspect
58
61
  end
@@ -27,13 +27,30 @@ module Async
27
27
  module Body
28
28
  # A dynamic body which you can write to and read from.
29
29
  class Writable < Readable
30
+ class Closed < StandardError
31
+ end
32
+
30
33
  def initialize
31
34
  @queue = Async::Queue.new
32
35
 
33
36
  @count = 0
34
37
 
35
38
  @finished = false
36
- @stopped = nil
39
+
40
+ @closed = false
41
+ @error = nil
42
+ end
43
+
44
+ # Stop generating output; cause the next call to write to fail with the given error.
45
+ def close(error = nil)
46
+ unless @closed
47
+ @queue.enqueue(nil)
48
+
49
+ @closed = true
50
+ @error = error
51
+ end
52
+
53
+ super
37
54
  end
38
55
 
39
56
  # Has the producer called #finish and has the reader consumed the nil token?
@@ -43,11 +60,6 @@ module Async
43
60
 
44
61
  # Read the next available chunk.
45
62
  def read
46
- # I'm not sure if this is a good idea.
47
- # if @stopped
48
- # raise @stopped
49
- # end
50
-
51
63
  return if @finished
52
64
 
53
65
  unless chunk = @queue.dequeue
@@ -57,17 +69,12 @@ module Async
57
69
  return chunk
58
70
  end
59
71
 
60
- # Stop generating output; cause the next call to write to fail with the given error.
61
- def stop(error)
62
- @stopped ||= error
63
- end
64
-
65
72
  # Write a single chunk to the body. Signal completion by calling `#finish`.
66
73
  def write(chunk)
67
74
  # If the reader breaks, the writer will break.
68
75
  # The inverse of this is less obvious (*)
69
- if @stopped
70
- raise @stopped
76
+ if @closed
77
+ raise(@error || Closed)
71
78
  end
72
79
 
73
80
  # TODO should this yield if the queue is full?
@@ -78,11 +85,6 @@ module Async
78
85
 
79
86
  alias << write
80
87
 
81
- # Signal that output has finished. This must be called at least once.
82
- def finish
83
- @queue.enqueue(nil)
84
- end
85
-
86
88
  def inspect
87
89
  "\#<#{self.class} #{@count} chunks written#{@finished ? ', finished' : ''}>"
88
90
  end
@@ -70,7 +70,7 @@ module Async
70
70
  end
71
71
 
72
72
  if end_stream
73
- @input.finish
73
+ @input.close
74
74
  end
75
75
  end
76
76
 
@@ -70,9 +70,9 @@ module Async
70
70
  end
71
71
 
72
72
  if end_stream
73
- @input.finish
73
+ @input.close
74
74
  end
75
- rescue EOFError
75
+ rescue
76
76
  @stream.send_reset_stream(0)
77
77
  end
78
78
 
@@ -56,7 +56,10 @@ module Async
56
56
  elsif chunk = @body.read
57
57
  # There was a new chunk of data to send
58
58
  else
59
- @body = nil
59
+ if @body
60
+ @body.close
61
+ @body = nil
62
+ end
60
63
 
61
64
  # @body.read above might take a while and a stream reset might be received in the mean time.
62
65
  unless closed?
@@ -109,7 +112,7 @@ module Async
109
112
  error_code = super
110
113
 
111
114
  if @body
112
- @body.stop(EOFError.new(error_code))
115
+ @body.close(EOFError.new(error_code))
113
116
  @body = nil
114
117
  end
115
118
 
@@ -75,7 +75,7 @@ module Async
75
75
  end
76
76
  end
77
77
 
78
- def stop(error)
78
+ def close(error = nil)
79
79
  complete_statistics(error)
80
80
 
81
81
  super
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module HTTP
23
- VERSION = "0.31.1"
23
+ VERSION = "0.32.0"
24
24
  end
25
25
  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.31.1
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-30 00:00:00.000000000 Z
11
+ date: 2018-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async