async-io 1.8.0 → 1.8.1

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: b298c4c118c511eaabda86500a8d08bf02b01cd156e0858cb962f4d3005ce665
4
- data.tar.gz: 1a231a883488b441d599991043409204b2f282df470fdd8b15d18afa6f9b8e06
3
+ metadata.gz: a8d2a5bb8ab12fac26be40774eb239426d8533b68b42d95866884e03fda6e824
4
+ data.tar.gz: 1cf9d4063d70649b936354195b83bd25eb49ff53b7a76d33178d2b80269cd319
5
5
  SHA512:
6
- metadata.gz: 8b87b6ca52a9e6164e4c6e549eaa2581d2c71908488f1f8235f0a2a8bbe25dd6e551a419b65f9ebd4be6b5c0182e99315c552cf36cc309777d311cd79397accc
7
- data.tar.gz: 1cd79fdb63398e13ce10041b4facf4bb1dc5498065c18eac8f3265cd2f842f6360b6f31e2b41acf11df29c62096810940050f4e51a7bceb4e9e242af9cfbf81d
6
+ metadata.gz: 7b58035212d0d4b063e5c511bfce3ded7f02e5e8524e4b0c47d2e654ca447d92f8f65441cd5ab577c413eacfff71e3ec1dd26c224fd72bf18decc00fcd791334
7
+ data.tar.gz: 3570983e37a2d827b5ead5bc7d0c2b36a2522bb95241ec54334923e999d2a51ec3829649ccd8eae9af1a501695d5f11c9b1d1469f0bb04508a5ccb2b4a0be938
@@ -75,6 +75,9 @@ module Async
75
75
  def self.wrap(socket, context)
76
76
  io = @wrapped_klass.new(socket.to_io, context)
77
77
 
78
+ # We detach the socket from the reactor, otherwise it's possible to add the file descriptor to the selector twice, which is bad.
79
+ socket.reactor = nil
80
+
78
81
  # This ensures that when the internal IO is closed, it also closes the internal socket:
79
82
  io.sync_close = true
80
83
 
@@ -24,7 +24,11 @@ require_relative 'generic'
24
24
  module Async
25
25
  module IO
26
26
  class Stream
27
- def initialize(io, block_size: 1024*8, sync: true)
27
+ # The default block size for IO buffers.
28
+ # BLOCK_SIZE = ENV.fetch('BLOCK_SIZE', 1024*16).to_i
29
+ BLOCK_SIZE = 1024*8
30
+
31
+ def initialize(io, block_size: BLOCK_SIZE, sync: true)
28
32
  @io = io
29
33
  @eof = false
30
34
 
@@ -45,11 +49,7 @@ module Async
45
49
  return '' if size == 0
46
50
 
47
51
  if size
48
- if size <= @block_size
49
- fill_read_buffer until @eof or @read_buffer.size >= size
50
- else
51
- fill_read_buffer(size - @read_buffer.size) until @eof or @read_buffer.size >= size
52
- end
52
+ fill_read_buffer until @eof or @read_buffer.size >= size
53
53
  else
54
54
  fill_read_buffer until @eof
55
55
  end
@@ -68,6 +68,28 @@ module Async
68
68
  return consume_read_buffer(size)
69
69
  end
70
70
 
71
+ # Efficiently read data from the stream until encountering pattern.
72
+ # @param pattern [String] The pattern to match.
73
+ # @return [String] The contents of the stream up until the pattern, which is consumed but not returned.
74
+ def read_until(pattern, offset = 0)
75
+ until index = @read_buffer.index(pattern, offset)
76
+ offset = @read_buffer.size
77
+
78
+ return unless fill_read_buffer
79
+ end
80
+
81
+ matched = @read_buffer.slice!(0, index)
82
+ @read_buffer.slice!(0, pattern.bytesize)
83
+
84
+ return matched
85
+ end
86
+
87
+ def peek
88
+ until yield(@read_buffer) || @eof
89
+ fill_read_buffer
90
+ end
91
+ end
92
+
71
93
  # Writes `string` to the buffer. When the buffer is full or #sync is true the
72
94
  # buffer is flushed to the underlying `io`.
73
95
  # @param string the string to write to the buffer.
@@ -79,7 +101,8 @@ module Async
79
101
  @write_buffer << string
80
102
 
81
103
  if @write_buffer.size >= @block_size
82
- flush
104
+ syswrite(@write_buffer)
105
+ @write_buffer.clear
83
106
  end
84
107
  end
85
108
 
@@ -117,8 +140,8 @@ module Async
117
140
 
118
141
  # Closes the stream and flushes any unwritten data.
119
142
  def close
120
- flush rescue nil
121
-
143
+ flush
144
+ ensure
122
145
  @io.close
123
146
  end
124
147
 
@@ -131,41 +154,24 @@ module Async
131
154
 
132
155
  alias eof eof?
133
156
 
134
- # Efficiently read data from the stream until encountering pattern.
135
- # @param pattern [String] The pattern to match.
136
- # @return [String] The contents of the stream up until the pattern, which is consumed but not returned.
137
- def read_until(pattern)
138
- index = @read_buffer.index(pattern)
139
-
140
- until index
141
- offset = @read_buffer.size
142
-
143
- fill_read_buffer
144
-
145
- return if @eof
146
-
147
- index = @read_buffer.index(pattern, offset)
148
- end
149
-
150
- matched = @read_buffer.slice!(0, index)
151
- @read_buffer.slice!(0, pattern.bytesize)
152
-
153
- return matched
154
- end
155
-
156
- def peek
157
- until yield(@read_buffer) || @eof
158
- fill_read_buffer
159
- end
160
- end
161
-
162
157
  private
163
158
 
164
159
  # Fills the buffer from the underlying stream.
165
- def fill_read_buffer(size = @block_size)
166
- if !sysread(size, @read_buffer)
167
- @eof = true
160
+ def fill_read_buffer
161
+ Async.logger.debug(self){"fill_read_buffer..."}
162
+
163
+ # Can we read directly into the buffer? (Ruby doesn't support append, only replace):
164
+ if chunk = @io.read(@block_size)
165
+ Async.logger.debug(self){"@io.read -> #{chunk.size} bytes"}
166
+ @read_buffer << chunk
167
+ return true
168
168
  end
169
+
170
+ Async.logger.debug(self){"@io.read -> #{chunk.inspect}"}
171
+
172
+ # We didn't read anything, so we must be at eof:
173
+ @eof = true
174
+ return false
169
175
  end
170
176
 
171
177
  # Consumes at most `size` bytes from the buffer.
@@ -209,15 +215,6 @@ module Async
209
215
 
210
216
  return written
211
217
  end
212
-
213
- # Read to
214
- def sysread(size, buffer)
215
- if buffer.empty?
216
- @io.read(size, buffer)
217
- elsif chunk = @io.read(size)
218
- buffer << chunk
219
- end
220
- end
221
218
  end
222
219
  end
223
220
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module IO
23
- VERSION = "1.8.0"
23
+ VERSION = "1.8.1"
24
24
  end
25
25
  end
@@ -49,6 +49,17 @@ RSpec.describe Async::IO::Stream do
49
49
  end
50
50
  end
51
51
 
52
+ describe '#read_until' do
53
+ it "can read a line" do
54
+ io.write("hello\nworld\n")
55
+ io.seek(0)
56
+
57
+ expect(stream.read_until("\n")).to be == 'hello'
58
+ expect(stream.read_until("\n")).to be == 'world'
59
+ expect(stream.read_until("\n")).to be_nil
60
+ end
61
+ end
62
+
52
63
  describe '#flush' do
53
64
  it "should not call write if write buffer is empty" do
54
65
  expect(io).to_not receive(:write)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.8.1
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-04-26 00:00:00.000000000 Z
11
+ date: 2018-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async