async-io 1.27.1 → 1.27.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +1 -1
- data/async-io.gemspec +2 -2
- data/lib/async/io/peer.rb +79 -0
- data/lib/async/io/server.rb +39 -0
- data/lib/async/io/socket.rb +2 -68
- data/lib/async/io/stream.rb +38 -35
- data/lib/async/io/unix_endpoint.rb +1 -1
- data/lib/async/io/version.rb +1 -1
- data/spec/async/io/endpoint_spec.rb +3 -0
- data/spec/async/io/shared_endpoint/server_spec.rb +6 -10
- data/spec/async/io/ssl_server_spec.rb +1 -1
- data/spec/async/io/ssl_socket_spec.rb +1 -1
- data/spec/async/io/stream_spec.rb +31 -0
- data/spec/async/io/udp_socket_spec.rb +1 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 484fda3385353976eaa6b5b52e3379264cb5a532369f9f036871c1525d6fad0d
|
4
|
+
data.tar.gz: 73a793c925d309ffdae29a364c656128e57192895fcad6d3f2c4673ffa7127ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86979dff7abe788e7aa8f867bbeab23a1dab2afab8bf5bed71700be231b9d91799187cc7758d58f0127efacdc39727d125ff49c83e92f42e1c97284ddad8a86b
|
7
|
+
data.tar.gz: 85c753ce6ffbc31dfdde378794c6969a80539c5c64a60ff3d3345620b0d27c793c8f2b44ef6fab9f084ad2c0d617da673e300264a2ab3cf530c9be7f1de0abcd
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Async::IO provides builds on [async] and provides asynchronous wrappers for `IO`
|
|
4
4
|
|
5
5
|
[async]: https://github.com/socketry/async
|
6
6
|
|
7
|
-
[![Build Status](https://
|
7
|
+
[![Build Status](https://travis-ci.com/socketry/async-io.svg?branch=master)](https://travis-ci.com/socketry/async-io)
|
8
8
|
[![Code Climate](https://codeclimate.com/github/socketry/async-io.svg)](https://codeclimate.com/github/socketry/async-io)
|
9
9
|
[![Coverage Status](https://coveralls.io/repos/socketry/async-io/badge.svg)](https://coveralls.io/r/socketry/async-io)
|
10
10
|
|
data/async-io.gemspec
CHANGED
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.required_ruby_version = '~> 2.3'
|
22
22
|
|
23
|
-
spec.add_development_dependency "async-container", "~> 0.
|
23
|
+
spec.add_development_dependency "async-container", "~> 0.15"
|
24
24
|
|
25
|
-
spec.add_development_dependency "bundler"
|
26
25
|
spec.add_development_dependency "covered"
|
26
|
+
spec.add_development_dependency "bundler"
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
29
|
end
|
@@ -0,0 +1,79 @@
|
|
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 'socket'
|
22
|
+
|
23
|
+
module Async
|
24
|
+
module IO
|
25
|
+
module Peer
|
26
|
+
include ::Socket::Constants
|
27
|
+
|
28
|
+
# Is it likely that the socket is still connected?
|
29
|
+
# May return false positive, but won't return false negative.
|
30
|
+
def connected?
|
31
|
+
return false if @io.closed?
|
32
|
+
|
33
|
+
# If we can wait for the socket to become readable, we know that the socket may still be open.
|
34
|
+
result = to_io.recv_nonblock(1, MSG_PEEK, exception: false)
|
35
|
+
|
36
|
+
# Either there was some data available, or we can wait to see if there is data avaialble.
|
37
|
+
return !result.empty? || result == :wait_readable
|
38
|
+
|
39
|
+
rescue Errno::ECONNRESET
|
40
|
+
# This might be thrown by recv_nonblock.
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
# Best effort to set *_NODELAY if it makes sense. Swallows errors where possible.
|
45
|
+
def sync=(value)
|
46
|
+
super
|
47
|
+
|
48
|
+
case self.protocol
|
49
|
+
when 0, IPPROTO_TCP
|
50
|
+
self.setsockopt(IPPROTO_TCP, TCP_NODELAY, value ? 1 : 0)
|
51
|
+
else
|
52
|
+
Async.logger.warn(self) {"Unsure how to sync=#{value} for #{self.protocol}!"}
|
53
|
+
end
|
54
|
+
rescue Errno::EINVAL
|
55
|
+
# On Darwin, sometimes occurs when the connection is not yet fully formed. Empirically, TCP_NODELAY is enabled despite this result.
|
56
|
+
rescue Errno::EOPNOTSUPP
|
57
|
+
# Some platforms may simply not support the operation.
|
58
|
+
# Async.logger.warn(self) {"Unable to set sync=#{value}!"}
|
59
|
+
end
|
60
|
+
|
61
|
+
def sync
|
62
|
+
case self.protocol
|
63
|
+
when IPPROTO_TCP
|
64
|
+
self.getsockopt(IPPROTO_TCP, TCP_NODELAY).bool
|
65
|
+
else
|
66
|
+
true
|
67
|
+
end && super
|
68
|
+
end
|
69
|
+
|
70
|
+
def type
|
71
|
+
self.local_address.socktype
|
72
|
+
end
|
73
|
+
|
74
|
+
def protocol
|
75
|
+
self.local_address.protocol
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,39 @@
|
|
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/task'
|
22
|
+
|
23
|
+
module Async
|
24
|
+
module IO
|
25
|
+
module Server
|
26
|
+
def accept_each(timeout: nil, task: Task.current)
|
27
|
+
task.annotate "accepting connections #{self.local_address.inspect} [fd=#{self.fileno}]"
|
28
|
+
|
29
|
+
callback = lambda do |io, address|
|
30
|
+
yield io, address, task: task
|
31
|
+
end
|
32
|
+
|
33
|
+
while true
|
34
|
+
self.accept(timeout: timeout, task: task, &callback)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/async/io/socket.rb
CHANGED
@@ -21,64 +21,12 @@
|
|
21
21
|
require 'socket'
|
22
22
|
require 'async/task'
|
23
23
|
|
24
|
+
require_relative 'peer'
|
25
|
+
require_relative 'server'
|
24
26
|
require_relative 'generic'
|
25
27
|
|
26
28
|
module Async
|
27
29
|
module IO
|
28
|
-
module Peer
|
29
|
-
include ::Socket::Constants
|
30
|
-
|
31
|
-
# Is it likely that the socket is still connected?
|
32
|
-
# May return false positive, but won't return false negative.
|
33
|
-
def connected?
|
34
|
-
return false if @io.closed?
|
35
|
-
|
36
|
-
# If we can wait for the socket to become readable, we know that the socket may still be open.
|
37
|
-
result = to_io.recv_nonblock(1, MSG_PEEK, exception: false)
|
38
|
-
|
39
|
-
# Either there was some data available, or we can wait to see if there is data avaialble.
|
40
|
-
return !result.empty? || result == :wait_readable
|
41
|
-
|
42
|
-
rescue Errno::ECONNRESET
|
43
|
-
# This might be thrown by recv_nonblock.
|
44
|
-
return false
|
45
|
-
end
|
46
|
-
|
47
|
-
# Best effort to set *_NODELAY if it makes sense. Swallows errors where possible.
|
48
|
-
def sync=(value)
|
49
|
-
super
|
50
|
-
|
51
|
-
case self.protocol
|
52
|
-
when 0, IPPROTO_TCP
|
53
|
-
self.setsockopt(IPPROTO_TCP, TCP_NODELAY, value ? 1 : 0)
|
54
|
-
else
|
55
|
-
Async.logger.warn(self) {"Unsure how to sync=#{value} for #{self.protocol}!"}
|
56
|
-
end
|
57
|
-
rescue Errno::EINVAL
|
58
|
-
# On Darwin, sometimes occurs when the connection is not yet fully formed. Empirically, TCP_NODELAY is enabled despite this result.
|
59
|
-
rescue Errno::EOPNOTSUPP
|
60
|
-
# Some platforms may simply not support the operation.
|
61
|
-
# Async.logger.warn(self) {"Unable to set sync=#{value}!"}
|
62
|
-
end
|
63
|
-
|
64
|
-
def sync
|
65
|
-
case self.protocol
|
66
|
-
when IPPROTO_TCP
|
67
|
-
self.getsockopt(IPPROTO_TCP, TCP_NODELAY).bool
|
68
|
-
else
|
69
|
-
true
|
70
|
-
end && super
|
71
|
-
end
|
72
|
-
|
73
|
-
def type
|
74
|
-
self.local_address.socktype
|
75
|
-
end
|
76
|
-
|
77
|
-
def protocol
|
78
|
-
self.local_address.protocol
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
30
|
class BasicSocket < Generic
|
83
31
|
wraps ::BasicSocket, :setsockopt, :connect_address, :close_read, :close_write, :local_address, :remote_address, :do_not_reverse_lookup, :do_not_reverse_lookup=, :shutdown, :getsockopt, :getsockname, :getpeername, :getpeereid
|
84
32
|
|
@@ -91,20 +39,6 @@ module Async
|
|
91
39
|
include Peer
|
92
40
|
end
|
93
41
|
|
94
|
-
module Server
|
95
|
-
def accept_each(timeout: nil, task: Task.current)
|
96
|
-
task.annotate "accepting connections #{self.local_address.inspect} [fd=#{self.fileno}]"
|
97
|
-
|
98
|
-
callback = lambda do |io, address|
|
99
|
-
yield io, address, task: task
|
100
|
-
end
|
101
|
-
|
102
|
-
while true
|
103
|
-
self.accept(timeout: timeout, task: task, &callback)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
42
|
class Socket < BasicSocket
|
109
43
|
wraps ::Socket, :bind, :ipv6only!, :listen
|
110
44
|
|
data/lib/async/io/stream.rb
CHANGED
@@ -21,6 +21,8 @@
|
|
21
21
|
require_relative 'buffer'
|
22
22
|
require_relative 'generic'
|
23
23
|
|
24
|
+
require 'async/semaphore'
|
25
|
+
|
24
26
|
module Async
|
25
27
|
module IO
|
26
28
|
class Stream
|
@@ -44,6 +46,7 @@ module Async
|
|
44
46
|
|
45
47
|
@deferred = deferred
|
46
48
|
@pending = 0
|
49
|
+
@writing = Async::Semaphore.new(1)
|
47
50
|
|
48
51
|
# We don't want Ruby to do any IO buffering.
|
49
52
|
@io.sync = sync
|
@@ -53,6 +56,7 @@ module Async
|
|
53
56
|
|
54
57
|
@read_buffer = Buffer.new
|
55
58
|
@write_buffer = Buffer.new
|
59
|
+
@drain_buffer = Buffer.new
|
56
60
|
|
57
61
|
# Used as destination buffer for underlying reads.
|
58
62
|
@input_buffer = Buffer.new
|
@@ -136,29 +140,8 @@ module Async
|
|
136
140
|
end
|
137
141
|
end
|
138
142
|
|
139
|
-
|
140
|
-
|
141
|
-
# @param string the string to write to the buffer.
|
142
|
-
# @return the number of bytes appended to the buffer.
|
143
|
-
def write(string)
|
144
|
-
if @write_buffer.empty? and string.bytesize >= @block_size
|
145
|
-
@io.write(string)
|
146
|
-
else
|
147
|
-
@write_buffer << string
|
148
|
-
|
149
|
-
if @write_buffer.bytesize >= @block_size
|
150
|
-
drain_write_buffer
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
return string.bytesize
|
155
|
-
end
|
156
|
-
|
157
|
-
# Writes `string` to the stream and returns self.
|
158
|
-
def <<(string)
|
159
|
-
write(string)
|
160
|
-
|
161
|
-
return self
|
143
|
+
def gets(separator = $/, **options)
|
144
|
+
read_until(separator, **options)
|
162
145
|
end
|
163
146
|
|
164
147
|
# Flushes buffered data to the stream.
|
@@ -176,8 +159,25 @@ module Async
|
|
176
159
|
end
|
177
160
|
end
|
178
161
|
|
179
|
-
|
180
|
-
|
162
|
+
# Writes `string` to the buffer. When the buffer is full or #sync is true the
|
163
|
+
# buffer is flushed to the underlying `io`.
|
164
|
+
# @param string the string to write to the buffer.
|
165
|
+
# @return the number of bytes appended to the buffer.
|
166
|
+
def write(string)
|
167
|
+
@write_buffer << string
|
168
|
+
|
169
|
+
if @write_buffer.bytesize >= @block_size
|
170
|
+
flush
|
171
|
+
end
|
172
|
+
|
173
|
+
return string.bytesize
|
174
|
+
end
|
175
|
+
|
176
|
+
# Writes `string` to the stream and returns self.
|
177
|
+
def <<(string)
|
178
|
+
write(string)
|
179
|
+
|
180
|
+
return self
|
181
181
|
end
|
182
182
|
|
183
183
|
def puts(*arguments, separator: $/)
|
@@ -201,7 +201,7 @@ module Async
|
|
201
201
|
end
|
202
202
|
|
203
203
|
def close_write
|
204
|
-
drain_write_buffer
|
204
|
+
drain_write_buffer unless @write_buffer.empty?
|
205
205
|
ensure
|
206
206
|
@io.close_write
|
207
207
|
end
|
@@ -242,17 +242,20 @@ module Async
|
|
242
242
|
private
|
243
243
|
|
244
244
|
def drain_write_buffer
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
245
|
+
@writing.acquire do
|
246
|
+
Async.logger.debug(self) do
|
247
|
+
if @pending > 0
|
248
|
+
"Draining #{@pending} writes (#{@write_buffer.bytesize} bytes)..."
|
249
|
+
else
|
250
|
+
"Draining immediate write (#{@write_buffer.bytesize} bytes)..."
|
251
|
+
end
|
250
252
|
end
|
253
|
+
|
254
|
+
@write_buffer, @drain_buffer = @drain_buffer, @write_buffer
|
255
|
+
|
256
|
+
@io.write(@drain_buffer)
|
257
|
+
@drain_buffer.clear
|
251
258
|
end
|
252
|
-
|
253
|
-
# Async.logger.debug(self, name: "write") {@write_buffer.inspect}
|
254
|
-
@io.write(@write_buffer)
|
255
|
-
@write_buffer.clear
|
256
259
|
end
|
257
260
|
|
258
261
|
# Fills the buffer from the underlying stream.
|
@@ -64,7 +64,7 @@ module Async
|
|
64
64
|
# @param options keyword arguments passed through to {UNIXEndpoint#initialize}
|
65
65
|
#
|
66
66
|
# @return [UNIXEndpoint]
|
67
|
-
def self.unix(path, type = ::Socket::SOCK_STREAM, **options)
|
67
|
+
def self.unix(path = "", type = ::Socket::SOCK_STREAM, **options)
|
68
68
|
UNIXEndpoint.new(path, type, **options)
|
69
69
|
end
|
70
70
|
end
|
data/lib/async/io/version.rb
CHANGED
@@ -24,8 +24,7 @@ require 'async/rspec/ssl'
|
|
24
24
|
require 'async/io/host_endpoint'
|
25
25
|
require 'async/io/shared_endpoint'
|
26
26
|
|
27
|
-
require 'async/container
|
28
|
-
require 'async/container/threaded'
|
27
|
+
require 'async/container'
|
29
28
|
|
30
29
|
RSpec.shared_examples_for Async::IO::SharedEndpoint do |container_class|
|
31
30
|
include_context Async::RSpec::SSL::VerifiedContexts
|
@@ -44,23 +43,20 @@ RSpec.shared_examples_for Async::IO::SharedEndpoint do |container_class|
|
|
44
43
|
let(:container) {container_class.new}
|
45
44
|
|
46
45
|
it "can use bound endpoint in container" do
|
47
|
-
container.
|
46
|
+
container.async do
|
48
47
|
bound_endpoint.accept do |peer|
|
49
48
|
peer.write "Hello World"
|
50
49
|
peer.close
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
expect(peer.read(11)).to eq "Hello World"
|
58
|
-
end
|
53
|
+
Async do
|
54
|
+
client_endpoint.connect do |peer|
|
55
|
+
expect(peer.read(11)).to eq "Hello World"
|
59
56
|
end
|
60
|
-
|
61
|
-
container.stop(false)
|
62
57
|
end
|
63
58
|
|
59
|
+
container.stop
|
64
60
|
bound_endpoint.close
|
65
61
|
end
|
66
62
|
end
|
@@ -46,6 +46,37 @@ RSpec.describe Async::IO::Stream do
|
|
46
46
|
|
47
47
|
it_should_behave_like Async::IO
|
48
48
|
|
49
|
+
describe '#drain_write_buffer' do
|
50
|
+
include_context Async::RSpec::Reactor
|
51
|
+
let(:output) {described_class.new(sockets.last)}
|
52
|
+
subject {described_class.new(sockets.first)}
|
53
|
+
|
54
|
+
let(:buffer_size) {1024*6}
|
55
|
+
|
56
|
+
it "can interleave calls to flush" do
|
57
|
+
tasks = 2.times.map do |i|
|
58
|
+
reactor.async do
|
59
|
+
buffer = i.to_s * buffer_size
|
60
|
+
128.times do
|
61
|
+
output.write(buffer)
|
62
|
+
output.flush
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
reactor.async do
|
68
|
+
tasks.each(&:wait)
|
69
|
+
output.close
|
70
|
+
end
|
71
|
+
|
72
|
+
Async::Task.current.sleep(1)
|
73
|
+
|
74
|
+
while buffer = subject.read(buffer_size)
|
75
|
+
expect(buffer).to be == (buffer[0] * buffer_size)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
49
80
|
describe '#close_read' do
|
50
81
|
subject {described_class.new(sockets.last)}
|
51
82
|
|
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.27.
|
4
|
+
version: 1.27.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -44,16 +44,16 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: '0.15'
|
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: 0.
|
54
|
+
version: '0.15'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: covered
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -148,8 +148,10 @@ files:
|
|
148
148
|
- lib/async/io/generic.rb
|
149
149
|
- lib/async/io/host_endpoint.rb
|
150
150
|
- lib/async/io/notification.rb
|
151
|
+
- lib/async/io/peer.rb
|
151
152
|
- lib/async/io/protocol/generic.rb
|
152
153
|
- lib/async/io/protocol/line.rb
|
154
|
+
- lib/async/io/server.rb
|
153
155
|
- lib/async/io/shared_endpoint.rb
|
154
156
|
- lib/async/io/socket.rb
|
155
157
|
- lib/async/io/socket_endpoint.rb
|
@@ -208,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
210
|
- !ruby/object:Gem::Version
|
209
211
|
version: '0'
|
210
212
|
requirements: []
|
211
|
-
rubygems_version: 3.
|
213
|
+
rubygems_version: 3.1.2
|
212
214
|
signing_key:
|
213
215
|
specification_version: 4
|
214
216
|
summary: Provides support for asynchonous TCP, UDP, UNIX and SSL sockets.
|