async 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.travis.yml +2 -0
- data/README.md +56 -38
- data/Rakefile +4 -0
- data/async.gemspec +4 -3
- data/lib/async/node.rb +47 -0
- data/lib/async/reactor.rb +27 -34
- data/lib/async/task.rb +35 -65
- data/lib/async/version.rb +1 -1
- data/lib/async/wrapper.rb +35 -19
- data/spec/async/condition_spec.rb +1 -1
- data/spec/async/node_spec.rb +37 -0
- data/spec/async/reactor/nested_spec.rb +1 -1
- data/spec/async/reactor_spec.rb +22 -1
- data/spec/async/task_spec.rb +53 -1
- data/{lib/async/udp_socket.rb → spec/async/wrapper_spec.rb} +25 -9
- data/spec/spec_helper.rb +2 -35
- metadata +14 -25
- data/examples/aio.rb +0 -42
- data/examples/echo.rb +0 -40
- data/lib/async/io.rb +0 -109
- data/lib/async/socket.rb +0 -109
- data/lib/async/tcp_socket.rb +0 -35
- data/lib/async/unix_socket.rb +0 -33
- data/spec/async/tcp_socket_spec.rb +0 -106
- data/spec/async/udp_socket_spec.rb +0 -71
- data/spec/async/unix_socket_spec.rb +0 -53
data/examples/aio.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'async'
|
4
|
-
|
5
|
-
reactor = Async::Reactor.new
|
6
|
-
|
7
|
-
puts "Creating server"
|
8
|
-
server = TCPServer.new("localhost", 6777)
|
9
|
-
|
10
|
-
REPEATS = 10
|
11
|
-
|
12
|
-
timer = reactor.after(1) do
|
13
|
-
puts "Reactor timed out!"
|
14
|
-
reactor.stop
|
15
|
-
end
|
16
|
-
|
17
|
-
reactor.async(server) do |server, task|
|
18
|
-
REPEATS.times do |i|
|
19
|
-
puts "Accepting peer on server #{server}"
|
20
|
-
task.with(server.accept) do |peer|
|
21
|
-
puts "Sending data to peer"
|
22
|
-
peer << "data #{i}"
|
23
|
-
peer.shutdown
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
puts "Server finished, canceling timer"
|
28
|
-
timer.cancel
|
29
|
-
end
|
30
|
-
|
31
|
-
REPEATS.times do |i|
|
32
|
-
# This aspect of the connection is synchronous.
|
33
|
-
puts "Creating client #{i}"
|
34
|
-
client = TCPSocket.new("localhost", 6777)
|
35
|
-
|
36
|
-
reactor.async(client) do |client|
|
37
|
-
puts "Reading data on client #{i}"
|
38
|
-
puts client.read(1024)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
reactor.run
|
data/examples/echo.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'async'
|
4
|
-
require 'async/tcp_socket'
|
5
|
-
|
6
|
-
def echo_server
|
7
|
-
Async::Reactor.run do |task|
|
8
|
-
# This is a synchronous block within the current task:
|
9
|
-
task.with(TCPServer.new('localhost', 9000)) do |server|
|
10
|
-
|
11
|
-
# This is an asynchronous block within the current reactor:
|
12
|
-
task.reactor.with(server.accept) do |client|
|
13
|
-
data = client.read(512)
|
14
|
-
|
15
|
-
task.sleep(rand)
|
16
|
-
|
17
|
-
client.write(data)
|
18
|
-
end while true
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def echo_client(data)
|
24
|
-
Async::Reactor.run do |task|
|
25
|
-
Async::TCPServer.connect('localhost', 9000) do |socket|
|
26
|
-
socket.write(data)
|
27
|
-
puts "echo_client: #{socket.read(512)}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
Async::Reactor.run do
|
33
|
-
server = echo_server
|
34
|
-
|
35
|
-
5.times.collect do |i|
|
36
|
-
echo_client("Hello World #{i}")
|
37
|
-
end.each(&:wait)
|
38
|
-
|
39
|
-
server.stop
|
40
|
-
end
|
data/lib/async/io.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require_relative 'wrapper'
|
22
|
-
|
23
|
-
require 'forwardable'
|
24
|
-
|
25
|
-
module Async
|
26
|
-
# Represents an asynchronous IO within a reactor.
|
27
|
-
class IO < Wrapper
|
28
|
-
extend Forwardable
|
29
|
-
|
30
|
-
WRAPPERS = {}
|
31
|
-
|
32
|
-
# Return the wrapper for a given native IO instance.
|
33
|
-
def self.[] instance
|
34
|
-
WRAPPERS[instance.class]
|
35
|
-
end
|
36
|
-
|
37
|
-
class << self
|
38
|
-
# @!macro [attach] wrap_blocking_method
|
39
|
-
# @method $1
|
40
|
-
# Invokes `$2` on the underlying {io}. If the operation would block, the current task is paused until the operation can succeed, at which point it's resumed and the operation is completed.
|
41
|
-
def wrap_blocking_method(new_name, method_name, &block)
|
42
|
-
if block_given?
|
43
|
-
define_method(new_name, &block)
|
44
|
-
else
|
45
|
-
define_method(new_name) do |*args|
|
46
|
-
async_send(method_name, *args)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def wraps(klass, *additional_methods)
|
52
|
-
WRAPPERS[klass] = self
|
53
|
-
|
54
|
-
# klass.instance_methods(false).grep(/(.*)_nonblock/) do |method_name|
|
55
|
-
# wrap_blocking_method($1, method_name)
|
56
|
-
# end
|
57
|
-
|
58
|
-
def_delegators :@io, *(additional_methods - instance_methods(false))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
wraps ::IO
|
63
|
-
|
64
|
-
# @example
|
65
|
-
# data = io.read(512)
|
66
|
-
wrap_blocking_method :read, :read_nonblock
|
67
|
-
|
68
|
-
# @example
|
69
|
-
# io.write("Hello World")
|
70
|
-
wrap_blocking_method :write, :write_nonblock
|
71
|
-
|
72
|
-
protected
|
73
|
-
|
74
|
-
if RUBY_VERSION >= "2.3"
|
75
|
-
def async_send(*args)
|
76
|
-
async do
|
77
|
-
@io.__send__(*args, exception: false)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
else
|
81
|
-
def async_send(*args)
|
82
|
-
async do
|
83
|
-
@io.__send__(*args)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def async
|
89
|
-
while true
|
90
|
-
begin
|
91
|
-
result = yield
|
92
|
-
|
93
|
-
case result
|
94
|
-
when :wait_readable
|
95
|
-
wait_readable
|
96
|
-
when :wait_writable
|
97
|
-
wait_writable
|
98
|
-
else
|
99
|
-
return result
|
100
|
-
end
|
101
|
-
rescue ::IO::WaitReadable
|
102
|
-
wait_readable
|
103
|
-
rescue ::IO::WaitWritable
|
104
|
-
wait_writable
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
data/lib/async/socket.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require_relative 'io'
|
22
|
-
|
23
|
-
require 'socket'
|
24
|
-
|
25
|
-
module Async
|
26
|
-
class BasicSocket < IO
|
27
|
-
wraps ::BasicSocket
|
28
|
-
|
29
|
-
wrap_blocking_method :recv, :recv_nonblock
|
30
|
-
wrap_blocking_method :recvmsg, :recvmsg_nonblock
|
31
|
-
|
32
|
-
wrap_blocking_method :recvfrom, :recvfrom_nonblock
|
33
|
-
|
34
|
-
wrap_blocking_method :send, :sendmsg_nonblock
|
35
|
-
wrap_blocking_method :sendmsg, :sendmsg_nonblock
|
36
|
-
end
|
37
|
-
|
38
|
-
class Socket < BasicSocket
|
39
|
-
wraps ::Socket
|
40
|
-
|
41
|
-
wrap_blocking_method :accept, :accept_nonblock
|
42
|
-
|
43
|
-
wrap_blocking_method :connect, :connect_nonblock do |*args|
|
44
|
-
begin
|
45
|
-
async_send(:connect_nonblock, *args)
|
46
|
-
rescue Errno::EISCONN
|
47
|
-
# We are now connected.
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Establish a connection to a given `remote_address`.
|
52
|
-
# @example
|
53
|
-
# socket = Async::Socket.connect(Addrinfo.tcp("8.8.8.8", 53))
|
54
|
-
# @param remote_address [Addrinfo] The remote address to connect to.
|
55
|
-
# @param local_address [Addrinfo] The local address to bind to before connecting.
|
56
|
-
# @option protcol [Integer] The socket protocol to use.
|
57
|
-
def self.connect(remote_address, local_address = nil, protocol: 0, task: Task.current)
|
58
|
-
socket = ::Socket.new(remote_address.afamily, remote_address.socktype, protocol)
|
59
|
-
|
60
|
-
if local_address
|
61
|
-
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
|
62
|
-
socket.bind(local_address) if local_address
|
63
|
-
end
|
64
|
-
|
65
|
-
if block_given?
|
66
|
-
task.with(socket) do |wrapper|
|
67
|
-
wrapper.connect(remote_address.to_sockaddr)
|
68
|
-
|
69
|
-
yield wrapper
|
70
|
-
end
|
71
|
-
else
|
72
|
-
task.bind(socket).connect(remote_address.to_sockaddr)
|
73
|
-
|
74
|
-
return socket
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Bind to a local address.
|
79
|
-
# @example
|
80
|
-
# socket = Async::Socket.bind(Addrinfo.tcp("0.0.0.0", 9090))
|
81
|
-
# @param local_address [Addrinfo] The local address to bind to.
|
82
|
-
# @option protcol [Integer] The socket protocol to use.
|
83
|
-
def self.bind(local_address, backlog: nil, protocol: 0, task: Task.current, &block)
|
84
|
-
socket = ::Socket.new(local_address.afamily, local_address.socktype, protocol)
|
85
|
-
|
86
|
-
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
|
87
|
-
socket.bind(local_address)
|
88
|
-
|
89
|
-
socket.listen(backlog) if backlog
|
90
|
-
|
91
|
-
if block_given?
|
92
|
-
task.with(socket, &block)
|
93
|
-
else
|
94
|
-
return socket
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Bind to a local address and accept connections in a loop.
|
99
|
-
def self.accept(*args, task: Task.current, &block)
|
100
|
-
bind(*args, task: task) do |wrapper|
|
101
|
-
task.with(*wrapper.accept, &block) while true
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
class IPSocket < BasicSocket
|
107
|
-
wraps ::IPSocket
|
108
|
-
end
|
109
|
-
end
|
data/lib/async/tcp_socket.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require_relative 'socket'
|
22
|
-
|
23
|
-
module Async
|
24
|
-
# Asynchronous TCP socket wrapper.
|
25
|
-
class TCPSocket < IPSocket
|
26
|
-
wraps ::TCPSocket
|
27
|
-
end
|
28
|
-
|
29
|
-
# Asynchronous TCP server wrappper.
|
30
|
-
class TCPServer < TCPSocket
|
31
|
-
wraps ::TCPServer
|
32
|
-
|
33
|
-
wrap_blocking_method :accept, :accept_nonblock
|
34
|
-
end
|
35
|
-
end
|
data/lib/async/unix_socket.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require_relative 'socket'
|
22
|
-
|
23
|
-
module Async
|
24
|
-
class UNIXServer < BasicSocket
|
25
|
-
wraps ::UNIXServer
|
26
|
-
|
27
|
-
wrap_blocking_method :accept, :accept_nonblock
|
28
|
-
end
|
29
|
-
|
30
|
-
class UNIXSocket < BasicSocket
|
31
|
-
wraps ::UNIXSocket
|
32
|
-
end
|
33
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
RSpec.describe Async::Reactor do
|
22
|
-
include_context "closes all io"
|
23
|
-
|
24
|
-
# Shared port for localhost network tests.
|
25
|
-
let(:server_address) {Addrinfo.tcp("localhost", 6779)}
|
26
|
-
let(:data) {"The quick brown fox jumped over the lazy dog."}
|
27
|
-
|
28
|
-
around(:each) do |example|
|
29
|
-
# Accept a single incoming connection and then finish.
|
30
|
-
subject.async do |task|
|
31
|
-
Async::Socket.bind(server_address, backlog: 128) do |server|
|
32
|
-
task.with(*server.accept) do |peer, address|
|
33
|
-
data = peer.read(512)
|
34
|
-
peer.write(data)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
result = example.run
|
40
|
-
|
41
|
-
return result if result.is_a? Exception
|
42
|
-
|
43
|
-
subject.run
|
44
|
-
end
|
45
|
-
|
46
|
-
describe 'basic tcp server' do
|
47
|
-
it "should start server and send data" do
|
48
|
-
subject.async do
|
49
|
-
Async::Socket.connect(server_address) do |client|
|
50
|
-
client.write(data)
|
51
|
-
expect(client.read(512)).to be == data
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe 'non-blocking tcp connect' do
|
58
|
-
it "should start server and send data" do
|
59
|
-
subject.async do |task|
|
60
|
-
Async::Socket.connect(server_address) do |client|
|
61
|
-
client.write(data)
|
62
|
-
expect(client.read(512)).to be == data
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
it "can connect socket and read/write in a different task" do
|
68
|
-
socket = nil
|
69
|
-
|
70
|
-
subject.async do |task|
|
71
|
-
socket = Async::Socket.connect(server_address)
|
72
|
-
|
73
|
-
# Stop the reactor once the connection was made.
|
74
|
-
subject.stop
|
75
|
-
end
|
76
|
-
|
77
|
-
subject.run
|
78
|
-
|
79
|
-
expect(socket).to_not be_nil
|
80
|
-
|
81
|
-
subject.async(socket) do |client|
|
82
|
-
client.write(data)
|
83
|
-
expect(client.read(512)).to be == data
|
84
|
-
end
|
85
|
-
|
86
|
-
subject.run
|
87
|
-
end
|
88
|
-
|
89
|
-
it "can't use a socket in nested tasks" do
|
90
|
-
subject.async do |task|
|
91
|
-
socket = Async::Socket.connect(server_address)
|
92
|
-
|
93
|
-
# I'm not sure if this is the right behaviour or not. Without a significant amont of work, async sockets are tied to the task that creates them.
|
94
|
-
expect do
|
95
|
-
subject.async(socket) do |client|
|
96
|
-
client.write(data)
|
97
|
-
expect(client.read(512)).to be == data
|
98
|
-
end
|
99
|
-
end.to raise_error(ArgumentError, /already registered with selector/)
|
100
|
-
|
101
|
-
# We need to explicitly close the socket, since we explicitly opened it.
|
102
|
-
socket.close
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|