async-io 1.2.1 → 1.3.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
- SHA1:
3
- metadata.gz: c21728ab9008e3a380403814866827866f69cfa5
4
- data.tar.gz: 9459dcb16dc458acf1724865b12a53dccf548dc5
2
+ SHA256:
3
+ metadata.gz: 152518b09c63b90c002c9e4fa832d075898c75e613cc0405e8b1df947f0c3bdd
4
+ data.tar.gz: 4ddb1b1b688bbc37bfc6beb705866706aba4f1e43efe53126b03e0f3f57c4733
5
5
  SHA512:
6
- metadata.gz: 60deebccccfc2885880c6a226b8f7637ec1234894efc92cc125e04778555a65f69e4dac73547c0e11de360c575830258fb32093353109bd08fe6cc351d404b6d
7
- data.tar.gz: 43de7fec9b8046f1b6fbb7be981671879d2f2ad7479d791a651b1aad82301edb834a64de0d7d66e4059f8111f2bc8b899970ff8f17c26da55e00806f04546fcb
6
+ metadata.gz: b057c8c881f386afa0151fa220a9b51660b2487d124e8c45dbc45c240c2c682e83fd16b8c92c69b311bc2ae0d3b638fec4218ceb7e76c417367fcbc0852ec9be
7
+ data.tar.gz: db8b25d2bbc5c069586ce61f17a030b9469d22b1173b618adf826dabdffe5251f3e4e387338adeb89fee93dafd303365e729cdf8cf3217401f9d306b10152e95
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.add_dependency "async", "~> 1.0"
20
20
  spec.add_development_dependency "async-rspec", "~> 1.2"
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1.13"
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.0"
25
25
  end
@@ -34,12 +34,17 @@ module Async
34
34
  self.send(uri.scheme, uri.host, uri.port, **options)
35
35
  end
36
36
 
37
+ # args: nodename, service, family, socktype, protocol, flags
37
38
  def tcp(*args, **options)
38
- AddressEndpoint.new(Address.tcp(*args), **options)
39
+ args[3] = ::Socket::SOCK_STREAM
40
+
41
+ HostEndpoint.new(args, **options)
39
42
  end
40
43
 
41
44
  def udp(*args, **options)
42
- AddressEndpoint.new(Address.udp(*args), **options)
45
+ args[3] = ::Socket::SOCK_DGRAM
46
+
47
+ HostEndpoint.new(args, **options)
43
48
  end
44
49
 
45
50
  def unix(*args, **options)
@@ -47,7 +52,7 @@ module Async
47
52
  end
48
53
 
49
54
  def ssl(*args, **options)
50
- SecureEndpoint.new(Endpoint.tcp(*args, **options), **options)
55
+ SecureEndpoint.new(self.tcp(*args, **options), **options)
51
56
  end
52
57
 
53
58
  # Generate a list of endpoints from an array.
@@ -76,32 +81,6 @@ module Async
76
81
  super(specification, options)
77
82
  end
78
83
 
79
- def address
80
- specification.local_address
81
- end
82
-
83
- def to_sockaddr
84
- address.to_sockaddr
85
- end
86
-
87
- # This is how addresses are internally converted, e.g. within `Socket#sendto`.
88
- alias to_str to_sockaddr
89
-
90
- # SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, etc.
91
- def socket_type
92
- address.socktype
93
- end
94
-
95
- # PF_* eg PF_INET etc, normally identical to AF_* constants.
96
- def socket_domain
97
- address.afamily
98
- end
99
-
100
- # IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IPX, etc.
101
- def socket_protocol
102
- address.protocol
103
- end
104
-
105
84
  def bind
106
85
  yield specification
107
86
  end
@@ -120,27 +99,50 @@ module Async
120
99
  end
121
100
  end
122
101
 
123
- # This class will open and close the socket automatically.
124
- class AddressEndpoint < Endpoint
125
- def address
126
- specification
102
+ class HostEndpoint < Endpoint
103
+ def bind(&block)
104
+ task = Task.current
105
+ tasks = []
106
+
107
+ task.annotate("binding to #{specification.inspect}")
108
+
109
+ Addrinfo.foreach(*specification).each do |address|
110
+ tasks << task.async do
111
+ Socket.bind(address, **options, &block)
112
+ end
113
+ end
114
+
115
+ tasks.each(&:wait)
127
116
  end
128
117
 
118
+ def connect(&block)
119
+ last_error = nil
120
+
121
+ Addrinfo.foreach(*specification).each do |address|
122
+ begin
123
+ return Socket.connect(address, &block)
124
+ rescue
125
+ last_error = $!
126
+ end
127
+ end
128
+
129
+ raise last_error
130
+ end
131
+ end
132
+
133
+ # This class will open and close the socket automatically.
134
+ class AddressEndpoint < Endpoint
129
135
  def bind(&block)
130
- Socket.bind(address, **options, &block)
136
+ Socket.bind(specification, **options, &block)
131
137
  end
132
138
 
133
139
  def connect(&block)
134
- Socket.connect(address, &block)
140
+ Socket.connect(specification, &block)
135
141
  end
136
142
  end
137
143
 
138
144
  # This class doesn't exert ownership over the specified socket, wraps a native ::IO.
139
145
  class SocketEndpoint < Endpoint
140
- def address
141
- specification.local_address
142
- end
143
-
144
146
  def bind(&block)
145
147
  yield Socket.new(specification)
146
148
  end
@@ -151,10 +153,6 @@ module Async
151
153
  end
152
154
 
153
155
  class SecureEndpoint < Endpoint
154
- def address
155
- specification.address
156
- end
157
-
158
156
  def hostname
159
157
  options[:hostname]
160
158
  end
@@ -93,7 +93,7 @@ module Async
93
93
 
94
94
  protected
95
95
 
96
- if RUBY_VERSION >= "2.3"
96
+ if RUBY_ENGINE == "ruby" and RUBY_VERSION >= "2.3"
97
97
  def async_send(*args)
98
98
  async do
99
99
  @io.__send__(*args, exception: false)
@@ -114,7 +114,7 @@ module Async
114
114
  end
115
115
  end
116
116
  end
117
- elsif RUBY_VERSION >= "2.1"
117
+ elsif RUBY_ENGINE == "ruby" and RUBY_VERSION >= "2.1"
118
118
  def async_send(*args)
119
119
  async do
120
120
  @io.__send__(*args)
@@ -0,0 +1,57 @@
1
+ # Copyright, 2018, 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 'generic'
22
+
23
+ module Async
24
+ module IO
25
+ # A cross-reactor/process notification pipe.
26
+ class Notification
27
+ def initialize
28
+ pipe = ::IO.pipe
29
+
30
+ @input = pipe.first
31
+ @output = pipe.last
32
+
33
+ @count = 0
34
+ end
35
+
36
+ def close
37
+ @input.close
38
+ @output.close
39
+ end
40
+
41
+ # Wait for signal to be called.
42
+ # @return [Object]
43
+ def wait
44
+ wrapper = Async::IO::Generic.new(@input)
45
+ wrapper.read(1)
46
+ ensure
47
+ wrapper.send(:close_monitor) if wrapper
48
+ end
49
+
50
+ # Signal to a given task that it should resume operations.
51
+ # @return [void]
52
+ def signal
53
+ @output.write(".")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -33,6 +33,10 @@ module Async
33
33
 
34
34
  wrap_blocking_method :sendmsg, :sendmsg_nonblock
35
35
  wrap_blocking_method :send, :sendmsg_nonblock, invert: false
36
+
37
+ def type
38
+ self.local_address.socktype
39
+ end
36
40
  end
37
41
 
38
42
  module ServerSocket
@@ -42,8 +46,8 @@ module Async
42
46
  wrapper = Socket.new(peer, self.reactor)
43
47
 
44
48
  if block_given?
45
- task.async do
46
- task.annotate "incoming connection #{address}"
49
+ task.async do |task|
50
+ task.annotate "incoming connection #{address.inspect}"
47
51
 
48
52
  begin
49
53
  yield wrapper, address
@@ -0,0 +1,64 @@
1
+ # Copyright, 2018, 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 'notification'
22
+
23
+ module Async
24
+ module IO
25
+ # A cross-reactor/process notification pipe.
26
+ class Trap
27
+ def initialize(name)
28
+ @name = name
29
+ @notifications = []
30
+ end
31
+
32
+ def install!
33
+ Signal.trap(@name, &self.method(:trigger))
34
+
35
+ return self
36
+ end
37
+
38
+ # Block the calling task until the signal occurs.
39
+ def trap
40
+ task = Task.current
41
+ task.annotate("waiting for signal #{@name}")
42
+
43
+ notification = Notification.new
44
+ @notifications << notification
45
+
46
+ while true
47
+ notification.wait
48
+ yield
49
+ end
50
+ ensure
51
+ if notification
52
+ notification.close
53
+ @notifications.delete(notification)
54
+ end
55
+ end
56
+
57
+ # Signal all waiting tasks that the trap occurred.
58
+ # @return [void]
59
+ def trigger(signal_number = nil)
60
+ @notifications.each(&:signal)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module IO
23
- VERSION = "1.2.1"
23
+ VERSION = "1.3.0"
24
24
  end
25
25
  end
@@ -18,28 +18,25 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'async/io/endpoint'
21
+ # This seems to break rbx
22
+ # require 'async/io/endpoint'
22
23
 
23
24
  RSpec.describe Async::IO::Endpoint do
24
25
  include_context Async::RSpec::Reactor
25
26
 
26
- describe Async::IO::Endpoint.tcp('0.0.0.0', 1234) do
27
+ describe Async::IO::Endpoint.tcp('0.0.0.0', 5234, reuse_port: true) do
27
28
  it "should be a tcp binding" do
28
- expect(subject.socket_type).to be == ::Socket::SOCK_STREAM
29
- end
30
-
31
- it "should generate valid address" do
32
- expect(subject.address).to be == Async::IO::Address.tcp('0.0.0.0', 1234)
29
+ subject.bind do |server|
30
+ expect(server.local_address.socktype).to be == ::Socket::SOCK_STREAM
31
+ end
33
32
  end
34
33
  end
35
34
 
36
35
  describe Async::IO::SocketEndpoint.new(TCPServer.new('0.0.0.0', 1234)) do
37
- it "should be a tcp binding" do
38
- expect(subject.socket_type).to be == ::Socket::SOCK_STREAM
39
- end
40
-
41
- it "should generate valid address" do
42
- expect(subject.address).to be == Async::IO::Address.tcp('0.0.0.0', 1234)
36
+ it "should bind to given socket" do
37
+ subject.bind do |server|
38
+ expect(server.io).to be == subject.specification
39
+ end
43
40
  end
44
41
  end
45
42
  end
@@ -0,0 +1,44 @@
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 'async/io/notification'
22
+
23
+ RSpec.describe Async::IO::Notification do
24
+ include_context Async::RSpec::Reactor
25
+
26
+ it "should wait for notification" do
27
+ waiting_task = reactor.async do
28
+ subject.wait
29
+ end
30
+
31
+ expect(waiting_task.status).to be :running
32
+
33
+ signalling_task = reactor.async do
34
+ subject.signal
35
+ end
36
+
37
+ signalling_task.wait
38
+ waiting_task.wait
39
+
40
+ expect(waiting_task.status).to be :complete
41
+
42
+ subject.close
43
+ end
44
+ end
@@ -27,7 +27,7 @@ RSpec.describe Async::Reactor do
27
27
  include_context Async::RSpec::SSL::VerifiedContexts
28
28
 
29
29
  # Shared port for localhost network tests.
30
- let(:endpoint) {Async::IO::Endpoint.tcp("localhost", 6779, reuse_port: true)}
30
+ let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6779, reuse_port: true)}
31
31
  let(:server_endpoint) {Async::IO::SecureEndpoint.new(endpoint, ssl_context: server_context)}
32
32
  let(:client_endpoint) {Async::IO::SecureEndpoint.new(endpoint, ssl_context: client_context)}
33
33
 
@@ -0,0 +1,44 @@
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 'async/io/trap'
22
+
23
+ RSpec.describe Async::IO::Trap do
24
+ include_context Async::RSpec::Reactor
25
+
26
+ subject {described_class.new(:USR1)}
27
+
28
+ it "should wait for signal" do
29
+ trapped = false
30
+
31
+ waiting_task = reactor.async do
32
+ subject.trap do
33
+ trapped = true
34
+ break
35
+ end
36
+ end
37
+
38
+ subject.trigger
39
+
40
+ waiting_task.wait
41
+
42
+ expect(trapped).to be_truthy
43
+ end
44
+ end
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.2.1
4
+ version: 1.3.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-02-07 00:00:00.000000000 Z
11
+ date: 2018-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.13'
47
+ version: '1.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.13'
54
+ version: '1.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -98,11 +98,13 @@ files:
98
98
  - lib/async/io/binary_string.rb
99
99
  - lib/async/io/endpoint.rb
100
100
  - lib/async/io/generic.rb
101
+ - lib/async/io/notification.rb
101
102
  - lib/async/io/protocol/line.rb
102
103
  - lib/async/io/socket.rb
103
104
  - lib/async/io/ssl_socket.rb
104
105
  - lib/async/io/stream.rb
105
106
  - lib/async/io/tcp_socket.rb
107
+ - lib/async/io/trap.rb
106
108
  - lib/async/io/udp_socket.rb
107
109
  - lib/async/io/unix_socket.rb
108
110
  - lib/async/io/version.rb
@@ -111,11 +113,13 @@ files:
111
113
  - spec/async/io/echo_spec.rb
112
114
  - spec/async/io/endpoint_spec.rb
113
115
  - spec/async/io/generic_spec.rb
116
+ - spec/async/io/notification_spec.rb
114
117
  - spec/async/io/protocol/line_spec.rb
115
118
  - spec/async/io/socket_spec.rb
116
119
  - spec/async/io/ssl_socket_spec.rb
117
120
  - spec/async/io/stream_spec.rb
118
121
  - spec/async/io/tcp_socket_spec.rb
122
+ - spec/async/io/trap_spec.rb
119
123
  - spec/async/io/udp_socket_spec.rb
120
124
  - spec/async/io/unix_socket_spec.rb
121
125
  - spec/async/io/wrap/tcp_spec.rb
@@ -139,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
143
  version: '0'
140
144
  requirements: []
141
145
  rubyforge_project:
142
- rubygems_version: 2.6.12
146
+ rubygems_version: 2.7.6
143
147
  signing_key:
144
148
  specification_version: 4
145
149
  summary: Provides support for asynchonous TCP, UDP, UNIX and SSL sockets.
@@ -148,11 +152,13 @@ test_files:
148
152
  - spec/async/io/echo_spec.rb
149
153
  - spec/async/io/endpoint_spec.rb
150
154
  - spec/async/io/generic_spec.rb
155
+ - spec/async/io/notification_spec.rb
151
156
  - spec/async/io/protocol/line_spec.rb
152
157
  - spec/async/io/socket_spec.rb
153
158
  - spec/async/io/ssl_socket_spec.rb
154
159
  - spec/async/io/stream_spec.rb
155
160
  - spec/async/io/tcp_socket_spec.rb
161
+ - spec/async/io/trap_spec.rb
156
162
  - spec/async/io/udp_socket_spec.rb
157
163
  - spec/async/io/unix_socket_spec.rb
158
164
  - spec/async/io/wrap/tcp_spec.rb