async-io 1.25.0 → 1.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/echo/client.rb +22 -0
- data/examples/echo/server.rb +57 -0
- data/lib/async/io/stream.rb +33 -5
- data/lib/async/io/trap.rb +23 -6
- data/lib/async/io/version.rb +1 -1
- data/spec/async/io/generic_spec.rb +1 -1
- data/spec/async/io/protocol/line_spec.rb +15 -9
- data/spec/async/io/trap_spec.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c73625346e61dc5ca64794c5fe70343437cf18e2f019a1fb7bba89d76eaaba6
|
4
|
+
data.tar.gz: 3fb2fbe3c6b50642b8ad3650b7829119c7f5b41ee8837569571e01a30364a4cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aca0fe4641f3066d1eb564b788a31ce5644a318281725342c8ee98f581d8af110c0c9b302e4d9b6e5816802234213d62da53dc34f0fc2715c173e9de79e03ad0
|
7
|
+
data.tar.gz: f318d5debbba3f6cad57d948cc3a16fb716c4bb79f5a84ec0cca5eee3edaadad983103c8188e3b6d83bb4db14393941c1750ba7955903efd8a7f79321e51d6e2
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
4
|
+
|
5
|
+
require 'async'
|
6
|
+
require 'async/io/trap'
|
7
|
+
require 'async/io/host_endpoint'
|
8
|
+
require 'async/io/stream'
|
9
|
+
|
10
|
+
endpoint = Async::IO::Endpoint.tcp('localhost', 4578)
|
11
|
+
|
12
|
+
Async do |task|
|
13
|
+
endpoint.connect do |peer|
|
14
|
+
stream = Async::IO::Stream.new(peer)
|
15
|
+
|
16
|
+
while true
|
17
|
+
task.sleep 1
|
18
|
+
stream.puts "Hello World!"
|
19
|
+
puts stream.gets.inspect
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
4
|
+
|
5
|
+
require 'async'
|
6
|
+
require 'async/io/trap'
|
7
|
+
require 'async/io/host_endpoint'
|
8
|
+
require 'async/io/stream'
|
9
|
+
|
10
|
+
endpoint = Async::IO::Endpoint.tcp('localhost', 4578)
|
11
|
+
|
12
|
+
interrupt = Async::IO::Trap.new(:INT)
|
13
|
+
|
14
|
+
Async do |top|
|
15
|
+
interrupt.install!
|
16
|
+
|
17
|
+
endpoint.bind do |server, task|
|
18
|
+
Async.logger.info(server) {"Accepting connections on #{server.local_address.inspect}"}
|
19
|
+
|
20
|
+
task.async do |subtask|
|
21
|
+
interrupt.wait
|
22
|
+
|
23
|
+
Async.logger.info(server) {"Closing server socket..."}
|
24
|
+
server.close
|
25
|
+
|
26
|
+
interrupt.default!
|
27
|
+
|
28
|
+
Async.logger.info(server) {"Waiting for connections to close..."}
|
29
|
+
subtask.sleep(4)
|
30
|
+
|
31
|
+
Async.logger.info(server) do |buffer|
|
32
|
+
buffer.puts "Stopping all tasks..."
|
33
|
+
task.print_hierarchy(buffer)
|
34
|
+
buffer.puts "", "Reactor Hierarchy"
|
35
|
+
task.reactor.print_hierarchy(buffer)
|
36
|
+
end
|
37
|
+
|
38
|
+
task.stop
|
39
|
+
end
|
40
|
+
|
41
|
+
server.listen(128)
|
42
|
+
|
43
|
+
server.accept_each do |peer|
|
44
|
+
stream = Async::IO::Stream.new(peer)
|
45
|
+
|
46
|
+
while chunk = stream.read_partial
|
47
|
+
Async.logger.debug(self) {chunk.inspect}
|
48
|
+
stream.write(chunk)
|
49
|
+
stream.flush
|
50
|
+
|
51
|
+
Async.logger.info(server) do |buffer|
|
52
|
+
task.reactor.print_hierarchy(buffer)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/async/io/stream.rb
CHANGED
@@ -38,10 +38,13 @@ module Async
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
def initialize(io, block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE, sync: true)
|
41
|
+
def initialize(io, block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE, sync: true, deferred: nil)
|
42
42
|
@io = io
|
43
43
|
@eof = false
|
44
44
|
|
45
|
+
@deferred = deferred
|
46
|
+
@pending = 0
|
47
|
+
|
45
48
|
# We don't want Ruby to do any IO buffering.
|
46
49
|
@io.sync = sync
|
47
50
|
|
@@ -55,6 +58,8 @@ module Async
|
|
55
58
|
@input_buffer = Buffer.new
|
56
59
|
end
|
57
60
|
|
61
|
+
attr_accessor :reactor
|
62
|
+
|
58
63
|
attr :io
|
59
64
|
attr :block_size
|
60
65
|
|
@@ -161,11 +166,34 @@ module Async
|
|
161
166
|
# Flushes buffered data to the stream.
|
162
167
|
def flush
|
163
168
|
unless @write_buffer.empty?
|
164
|
-
@
|
165
|
-
|
169
|
+
if @deferred and task = Task.current
|
170
|
+
if @pending.zero?
|
171
|
+
task.reactor << self
|
172
|
+
end
|
173
|
+
|
174
|
+
@pending += 1
|
175
|
+
else
|
176
|
+
Async.logger.debug(self) {"Flushing immediate write (#{@write_buffer.bytesize} bytes)..."}
|
177
|
+
|
178
|
+
@io.write(@write_buffer)
|
179
|
+
@write_buffer.clear
|
180
|
+
@pending = 0
|
181
|
+
end
|
166
182
|
end
|
167
183
|
end
|
168
184
|
|
185
|
+
def alive?
|
186
|
+
@pending > 0
|
187
|
+
end
|
188
|
+
|
189
|
+
def resume
|
190
|
+
Async.logger.debug(self) {"Flushing #{@pending} writes (#{@write_buffer.bytesize} bytes)..."}
|
191
|
+
|
192
|
+
@io.write(@write_buffer)
|
193
|
+
@write_buffer.clear
|
194
|
+
@pending = 0
|
195
|
+
end
|
196
|
+
|
169
197
|
def gets(separator = $/, **options)
|
170
198
|
read_until(separator, **options)
|
171
199
|
end
|
@@ -191,7 +219,7 @@ module Async
|
|
191
219
|
end
|
192
220
|
|
193
221
|
def close_write
|
194
|
-
|
222
|
+
resume unless @write_buffer.empty?
|
195
223
|
ensure
|
196
224
|
@io.close_write
|
197
225
|
end
|
@@ -201,7 +229,7 @@ module Async
|
|
201
229
|
return if @io.closed?
|
202
230
|
|
203
231
|
begin
|
204
|
-
|
232
|
+
resume unless @write_buffer.empty?
|
205
233
|
rescue
|
206
234
|
# We really can't do anything here unless we want #close to raise exceptions.
|
207
235
|
ensure
|
data/lib/async/io/trap.rb
CHANGED
@@ -36,7 +36,11 @@ module Async
|
|
36
36
|
|
37
37
|
# Ignore the trap within the current process. Can be invoked before forking and/or invoking `install!` to assert default behaviour.
|
38
38
|
def ignore!
|
39
|
-
Signal.trap(@name,
|
39
|
+
Signal.trap(@name, :IGNORE)
|
40
|
+
end
|
41
|
+
|
42
|
+
def default!
|
43
|
+
Signal.trap(@name, :DEFAULT)
|
40
44
|
end
|
41
45
|
|
42
46
|
# Install the trap into the current process. Thread safe.
|
@@ -55,17 +59,21 @@ module Async
|
|
55
59
|
return true
|
56
60
|
end
|
57
61
|
|
58
|
-
#
|
59
|
-
|
60
|
-
|
62
|
+
# Wait until the signal occurs. If a block is given, execute in a loop.
|
63
|
+
# @yield [Async::Task] the current task.
|
64
|
+
def wait(task: Task.current, &block)
|
61
65
|
task.annotate("waiting for signal #{@name}")
|
62
66
|
|
63
67
|
notification = Notification.new
|
64
68
|
@notifications << notification
|
65
69
|
|
66
|
-
|
70
|
+
if block_given?
|
71
|
+
while true
|
72
|
+
notification.wait
|
73
|
+
yield task
|
74
|
+
end
|
75
|
+
else
|
67
76
|
notification.wait
|
68
|
-
yield
|
69
77
|
end
|
70
78
|
ensure
|
71
79
|
if notification
|
@@ -74,6 +82,15 @@ module Async
|
|
74
82
|
end
|
75
83
|
end
|
76
84
|
|
85
|
+
# Deprecated.
|
86
|
+
alias trap wait
|
87
|
+
|
88
|
+
def async(parent: Task.current, &block)
|
89
|
+
parent.async do |task|
|
90
|
+
self.trap(task: task, &block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
77
94
|
# Signal all waiting tasks that the trap occurred.
|
78
95
|
# @return [void]
|
79
96
|
def trigger(signal_number = nil)
|
data/lib/async/io/version.rb
CHANGED
@@ -28,7 +28,7 @@ RSpec.describe Async::IO::Generic do
|
|
28
28
|
|
29
29
|
CONSOLE_METHODS = [:beep, :cooked, :cooked!, :cursor, :cursor=, :echo=, :echo?,:getch, :getpass, :goto, :iflush, :ioflush, :noecho, :oflush,:pressed?, :raw, :raw!, :winsize, :winsize=]
|
30
30
|
# On TruffleRuby, IO#encode_with needs to be defined for YAML.dump as a public method, allow it
|
31
|
-
ignore = [:encode_with]
|
31
|
+
ignore = [:encode_with, :check_winsize_changed, :clear_screen, :console_mode, :console_mode=, :cursor_down, :cursor_left, :cursor_right, :cursor_up, :erase_line, :erase_screen, :goto_column, :scroll_backward, :scroll_forward]
|
32
32
|
|
33
33
|
it_should_behave_like Async::IO::Generic, [
|
34
34
|
:bytes, :chars, :codepoints, :each, :each_byte, :each_char, :each_codepoint, :each_line, :getbyte, :getc, :gets, :lineno, :lineno=, :lines, :print, :printf, :putc, :puts, :readbyte, :readchar, :readline, :readlines, :ungetbyte, :ungetc
|
@@ -19,14 +19,19 @@
|
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
21
|
require 'async/io/protocol/line'
|
22
|
+
require 'async/io/socket'
|
22
23
|
|
23
24
|
RSpec.describe Async::IO::Protocol::Line do
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
include_context Async::RSpec::Reactor
|
26
|
+
|
27
|
+
let(:pipe) {@pipe = Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)}
|
28
|
+
let(:remote) {pipe.first}
|
29
|
+
subject {described_class.new(Async::IO::Stream.new(pipe.last, deferred: true), "\n")}
|
30
|
+
|
31
|
+
after(:each) {@pipe&.each(&:close)}
|
27
32
|
|
28
33
|
context "default line ending" do
|
29
|
-
subject {described_class.new(
|
34
|
+
subject {described_class.new(nil)}
|
30
35
|
|
31
36
|
it "should have default eol terminator" do
|
32
37
|
expect(subject.eol).to_not be_nil
|
@@ -36,15 +41,16 @@ RSpec.describe Async::IO::Protocol::Line do
|
|
36
41
|
describe '#write_lines' do
|
37
42
|
it "should write line" do
|
38
43
|
subject.write_lines "Hello World"
|
44
|
+
subject.close
|
39
45
|
|
40
|
-
expect(
|
46
|
+
expect(remote.read).to be == "Hello World\n"
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
44
50
|
describe '#read_line' do
|
45
51
|
before(:each) do
|
46
|
-
|
47
|
-
|
52
|
+
remote.write "Hello World\n"
|
53
|
+
remote.close
|
48
54
|
end
|
49
55
|
|
50
56
|
it "should read one line" do
|
@@ -58,8 +64,8 @@ RSpec.describe Async::IO::Protocol::Line do
|
|
58
64
|
|
59
65
|
describe '#read_lines' do
|
60
66
|
before(:each) do
|
61
|
-
|
62
|
-
|
67
|
+
remote.write "Hello\nWorld\n"
|
68
|
+
remote.close
|
63
69
|
end
|
64
70
|
|
65
71
|
it "should read multiple lines" do
|
data/spec/async/io/trap_spec.rb
CHANGED
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.
|
4
|
+
version: 1.26.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: 2019-
|
11
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -129,6 +129,8 @@ files:
|
|
129
129
|
- examples/allocations/read_chunks.rb
|
130
130
|
- examples/chat/client.rb
|
131
131
|
- examples/chat/server.rb
|
132
|
+
- examples/echo/client.rb
|
133
|
+
- examples/echo/server.rb
|
132
134
|
- examples/issues/broken_ssl.rb
|
133
135
|
- examples/issues/pipes.rb
|
134
136
|
- examples/millions/client.rb
|
@@ -206,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
208
|
- !ruby/object:Gem::Version
|
207
209
|
version: '0'
|
208
210
|
requirements: []
|
209
|
-
rubygems_version: 3.0.
|
211
|
+
rubygems_version: 3.0.4
|
210
212
|
signing_key:
|
211
213
|
specification_version: 4
|
212
214
|
summary: Provides support for asynchonous TCP, UDP, UNIX and SSL sockets.
|