async-io 1.18.5 → 1.20.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: 4521c94506778f0d7e6f5dec2fe76bf6b6f0374ae3c327e29775063bd3393aaa
4
- data.tar.gz: 56d1f0388b1d1a64a87dbb5086bcbd209602933ab805fae44ea6e699cc3eba8b
3
+ metadata.gz: 69adfd1cd876361c3b94bc80a5f5c164d45df0156a37c6f9fc54542a79bc443c
4
+ data.tar.gz: 32758166362e4780b7d251d4f649cdc2eb14fd4ab48a378be94968c5719053df
5
5
  SHA512:
6
- metadata.gz: 7c84cb8f453e9b7c7f80af18443d04eaeca38e46172afbc1ec4f6c219123449a5b8744d72db0c282e2d3da8826f29aa64f331698608a589c9c35a761bc6531f4
7
- data.tar.gz: 027bf4fc6e910b3e1fdf883f7aa6a98045131f43318a014f77bb6e1734d9e932f95bd54fb23b9237e9ef78bccb1f70fc52c424ece21020e31663ea3a6b151ffe
6
+ metadata.gz: 9fc9a5d6e563b8dbe9b2c700ce284ae905efb90a338b79ebed4daff5368912707355fe40efcbda243948e061bd0b143cd8e4bf22bf232dbc9afcf9d93aa5356b
7
+ data.tar.gz: 94d7271c1c6e50a84c3120ae408989b2caeab045a8b07e54d417d4bc6159eea35138cc20cc86ba879d4492e457aee75eaa078ad23d2826c80c21fa12ed24d128
data/Gemfile CHANGED
@@ -12,7 +12,5 @@ group :test do
12
12
  gem 'benchmark-ips'
13
13
  gem 'ruby-prof', platforms: :mri
14
14
 
15
- gem 'async-container'
16
-
17
15
  gem 'http'
18
16
  end
@@ -19,7 +19,9 @@ Gem::Specification.new do |spec|
19
19
  spec.add_development_dependency "async-rspec", "~> 1.10"
20
20
 
21
21
  spec.required_ruby_version = '~> 2.3'
22
-
22
+
23
+ spec.add_development_dependency "async-container", "~> 0.10.0"
24
+
23
25
  spec.add_development_dependency "bundler"
24
26
  spec.add_development_dependency "covered"
25
27
  spec.add_development_dependency "rake", "~> 10.0"
@@ -20,7 +20,9 @@ puts "Starting #{CONCURRENCY} processes, running #{TASKS} tasks, making #{REPEAT
20
20
  puts "Total number of connections: #{CONCURRENCY * TASKS * REPEATS}!"
21
21
 
22
22
  begin
23
- container = Async::Container::Forked.new(concurrency: CONCURRENCY) do
23
+ container = Async::Container::Forked.new
24
+
25
+ container.run(count: CONCURRENCY) do
24
26
  Async do |task|
25
27
  connections = []
26
28
 
@@ -28,7 +28,6 @@ module Async
28
28
  super(**options)
29
29
 
30
30
  @address = address
31
- @options = options
32
31
  end
33
32
 
34
33
  def to_s
@@ -36,7 +35,6 @@ module Async
36
35
  end
37
36
 
38
37
  attr :address
39
- attr :options
40
38
 
41
39
  # Bind a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
42
40
  # @yield [Socket] the bound socket
@@ -51,11 +49,5 @@ module Async
51
49
  Socket.connect(@address, **@options, &block)
52
50
  end
53
51
  end
54
-
55
- class Endpoint
56
- def self.unix(*args, **options)
57
- AddressEndpoint.new(Address.unix(*args), **options)
58
- end
59
- end
60
52
  end
61
53
  end
@@ -50,10 +50,13 @@ module Async
50
50
  when 0, Socket::IPPROTO_TCP
51
51
  self.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, value ? 1 : 0)
52
52
  else
53
- warn "Unsure how to sync=#{value} for #{self.protocol}!"
53
+ Async.logger.warn(self) {"Unsure how to sync=#{value} for #{self.protocol}!"}
54
54
  end
55
55
  rescue Errno::EINVAL
56
56
  # On Darwin, sometimes occurs when the connection is not yet fully formed. Empirically, TCP_NODELAY is enabled despite this result.
57
+ rescue Errno::EOPNOTSUPP
58
+ # Some platforms may simply not support the operation.
59
+ Async.logger.warn(self) {"Unable to set sync=#{value}!"}
57
60
  end
58
61
 
59
62
  def sync
@@ -138,6 +141,7 @@ module Async
138
141
  alias accept_nonblock accept
139
142
  alias sysaccept accept
140
143
 
144
+ # Build and wrap the underlying io.
141
145
  def self.build(*args, timeout: nil, task: Task.current)
142
146
  socket = wrapped_klass.new(*args)
143
147
 
@@ -0,0 +1,67 @@
1
+ # Copyright, 2019, 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 'address_endpoint'
22
+
23
+ module Async
24
+ module IO
25
+ # This class doesn't exert ownership over the specified unix socket and ensures exclusive access by using `flock` where possible.
26
+ class UNIXEndpoint < AddressEndpoint
27
+ def initialize(path, type, **options)
28
+ # I wonder if we should implement chdir behaviour in here if path is longer than 104 characters.
29
+ super(Address.unix(path, type), **options)
30
+
31
+ @path = path
32
+ end
33
+
34
+ def to_s
35
+ "\#<#{self.class} #{@path.inspect}>"
36
+ end
37
+
38
+ attr :path
39
+
40
+ def bound?
41
+ self.connect do
42
+ return true
43
+ end
44
+ rescue Errno::ECONNREFUSED
45
+ return false
46
+ end
47
+
48
+ def bind(&block)
49
+ Socket.bind(@address, **@options, &block)
50
+ rescue Errno::EADDRINUSE
51
+ # If you encounter EADDRINUSE from `bind()`, you can check if the socket is actually accepting connections by attempting to `connect()` to it. If the socket is still bound by an active process, the connection will succeed. Otherwise, it should be safe to `unlink()` the path and try again.
52
+ if !bound? && File.exist?(@path)
53
+ File.unlink(@path)
54
+ retry
55
+ else
56
+ raise
57
+ end
58
+ end
59
+ end
60
+
61
+ class Endpoint
62
+ def self.unix(path, type = ::Socket::SOCK_STREAM, **options)
63
+ UNIXEndpoint.new(path, type, **options)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module IO
23
- VERSION = "1.18.5"
23
+ VERSION = "1.20.0"
24
24
  end
25
25
  end
@@ -41,21 +41,26 @@ RSpec.shared_examples_for Async::IO::SharedEndpoint do |container_class|
41
41
  end.wait
42
42
  end
43
43
 
44
+ let(:container) {container_class.new}
45
+
44
46
  it "can use bound endpoint in container" do
45
- container = container_class.new(concurrency: 1) do
47
+ container.run(count: 1) do
46
48
  bound_endpoint.accept do |peer|
47
49
  peer.write "Hello World"
48
50
  peer.close
49
51
  end
50
52
  end
51
53
 
52
- Async do
53
- client_endpoint.connect do |peer|
54
- expect(peer.read(11)).to eq "Hello World"
54
+ container.wait do
55
+ Async do
56
+ client_endpoint.connect do |peer|
57
+ expect(peer.read(11)).to eq "Hello World"
58
+ end
55
59
  end
60
+
61
+ container.stop(false)
56
62
  end
57
63
 
58
- container.stop
59
64
  bound_endpoint.close
60
65
  end
61
66
  end
@@ -0,0 +1,78 @@
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/unix_endpoint'
22
+
23
+ RSpec.describe Async::IO::UNIXEndpoint do
24
+ include_context Async::RSpec::Reactor
25
+
26
+ let(:data) {"The quick brown fox jumped over the lazy dog."}
27
+ let(:path) {File.join(__dir__, "unix-socket")}
28
+ subject {described_class.unix(path)}
29
+
30
+ before(:each) do
31
+ FileUtils.rm_f path
32
+ end
33
+
34
+ after do
35
+ FileUtils.rm_f path
36
+ end
37
+
38
+ it "should echo data back to peer" do
39
+ server_task = reactor.async do
40
+ subject.accept do |peer|
41
+ peer.send(peer.recv(512))
42
+ end
43
+ end
44
+
45
+ reactor.async do
46
+ subject.connect do |client|
47
+ client.send(data)
48
+
49
+ response = client.recv(512)
50
+
51
+ expect(response).to be == data
52
+ end
53
+ end.wait
54
+
55
+ server_task.stop
56
+ end
57
+
58
+ it "should fails to bind if there is an existing binding" do
59
+ condition = Async::Condition.new
60
+
61
+ reactor.async do
62
+ condition.wait
63
+
64
+ expect do
65
+ subject.bind
66
+ end.to raise_error(Errno::EADDRINUSE)
67
+ end
68
+
69
+ server_task = reactor.async do
70
+ subject.bind do |server|
71
+ server.listen(1)
72
+ condition.signal
73
+ end
74
+ end
75
+
76
+ server_task.stop
77
+ end
78
+ 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.18.5
4
+ version: 1.20.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-02-24 00:00:00.000000000 Z
11
+ date: 2019-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: async-container
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.10.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.10.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +153,7 @@ files:
139
153
  - lib/async/io/tcp_socket.rb
140
154
  - lib/async/io/trap.rb
141
155
  - lib/async/io/udp_socket.rb
156
+ - lib/async/io/unix_endpoint.rb
142
157
  - lib/async/io/unix_socket.rb
143
158
  - lib/async/io/version.rb
144
159
  - spec/addrinfo.rb
@@ -162,6 +177,7 @@ files:
162
177
  - spec/async/io/tcp_socket_spec.rb
163
178
  - spec/async/io/trap_spec.rb
164
179
  - spec/async/io/udp_socket_spec.rb
180
+ - spec/async/io/unix_endpoint_spec.rb
165
181
  - spec/async/io/unix_socket_spec.rb
166
182
  - spec/async/io/wrap/http_rb_spec.rb
167
183
  - spec/async/io/wrap/tcp_spec.rb
@@ -211,6 +227,7 @@ test_files:
211
227
  - spec/async/io/tcp_socket_spec.rb
212
228
  - spec/async/io/trap_spec.rb
213
229
  - spec/async/io/udp_socket_spec.rb
230
+ - spec/async/io/unix_endpoint_spec.rb
214
231
  - spec/async/io/unix_socket_spec.rb
215
232
  - spec/async/io/wrap/http_rb_spec.rb
216
233
  - spec/async/io/wrap/tcp_spec.rb