io-endpoint 0.1.0 → 0.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/io/endpoint/address_endpoint.rb +5 -4
- data/lib/io/endpoint/composite_endpoint.rb +12 -6
- data/lib/io/endpoint/generic.rb +5 -26
- data/lib/io/endpoint/host_endpoint.rb +20 -16
- data/lib/io/endpoint/shared_endpoint.rb +58 -25
- data/lib/io/endpoint/ssl_endpoint.rb +43 -16
- data/lib/io/endpoint/unix_endpoint.rb +4 -2
- data/lib/io/endpoint/version.rb +1 -1
- data/lib/io/endpoint/wrapper.rb +28 -5
- data/readme.md +8 -0
- data.tar.gz.sig +3 -1
- metadata +4 -46
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c519269d1e8459a607159be713100765c2e424f199a08cce97e1ba6c877b5b6a
|
4
|
+
data.tar.gz: ee2e142c5320d9412395c80098e669971b8956b43ad58252d52a85e2a97a5a97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67ce6a415b998cd1d072a1faee146803f30de818666278846cbdf69f8f72fd8c30d0df371ec44747a2ea74a1fdd0d86f100e187ba15d17275ffbb335d29e6df5
|
7
|
+
data.tar.gz: 360a4f1ee5e162e71be467b0090e54eade25f141abde4452f6ba0e389def1398eaabfe5f76aaed4cbf333ba0c40334e014029d7fb76e13d09ff60f428ac63d9f
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -17,16 +17,17 @@ module IO::Endpoint
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def to_s
|
20
|
-
"\#<#{self.class}
|
20
|
+
"\#<#{self.class} address=#{@address.inspect}>"
|
21
21
|
end
|
22
22
|
|
23
23
|
attr :address
|
24
24
|
|
25
25
|
# Bind a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
|
26
|
-
# @yield
|
27
|
-
#
|
26
|
+
# @yield {|socket| ...} An optional block which will be passed the socket.
|
27
|
+
# @parameter socket [Socket] The socket which has been bound.
|
28
|
+
# @return [Array(Socket)] the bound socket
|
28
29
|
def bind(wrapper = Wrapper.default, &block)
|
29
|
-
wrapper.bind(@address, **@options, &block)
|
30
|
+
[wrapper.bind(@address, **@options, &block)]
|
30
31
|
end
|
31
32
|
|
32
33
|
# Connects a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
|
@@ -13,7 +13,9 @@ module IO::Endpoint
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def each(&block)
|
16
|
-
@endpoints.each
|
16
|
+
@endpoints.each do |endpoint|
|
17
|
+
endpoint.each(&block)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
def connect(&block)
|
@@ -30,13 +32,17 @@ module IO::Endpoint
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def bind(&block)
|
33
|
-
|
35
|
+
if block_given?
|
36
|
+
@endpoints.each do |endpoint|
|
37
|
+
endpoint.bind(&block)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
@endpoints.map(&:bind).flatten.compact
|
41
|
+
end
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
CompositeEndpoint.new(endpoints, **options)
|
40
|
-
end
|
45
|
+
def self.composite(*endpoints, **options)
|
46
|
+
CompositeEndpoint.new(endpoints, **options)
|
41
47
|
end
|
42
48
|
end
|
data/lib/io/endpoint/generic.rb
CHANGED
@@ -77,30 +77,15 @@ module IO::Endpoint
|
|
77
77
|
socket, address = server.accept
|
78
78
|
|
79
79
|
Fiber.schedule do
|
80
|
-
yield
|
80
|
+
yield socket, address
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
#
|
87
|
-
#
|
88
|
-
|
89
|
-
wrappers = []
|
90
|
-
|
91
|
-
self.each do |endpoint|
|
92
|
-
wrapper = endpoint.bind
|
93
|
-
wrappers << wrapper
|
94
|
-
|
95
|
-
yield wrapper
|
96
|
-
end
|
97
|
-
|
98
|
-
return wrappers
|
99
|
-
ensure
|
100
|
-
wrappers.each(&:close) if $!
|
101
|
-
end
|
102
|
-
|
103
|
-
# Create an Endpoint instance by URI scheme. The host and port of the URI will be passed to the Endpoint factory method, along with any options.
|
86
|
+
# Create an Endpoint instance by URI scheme. The host and port of the URI will be passed to the Endpoint factory method, along with any options.\
|
87
|
+
#
|
88
|
+
# You should not use untrusted input as it may execute arbitrary code.
|
104
89
|
#
|
105
90
|
# @param string [String] URI as string. Scheme will decide implementation used.
|
106
91
|
# @param options keyword arguments passed through to {#initialize}
|
@@ -112,13 +97,7 @@ module IO::Endpoint
|
|
112
97
|
def self.parse(string, **options)
|
113
98
|
uri = URI.parse(string)
|
114
99
|
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
protected
|
119
|
-
|
120
|
-
def accepted(socket)
|
121
|
-
socket
|
100
|
+
IO::Endpoint.public_send(uri.scheme, uri.host, uri.port, **options)
|
122
101
|
end
|
123
102
|
end
|
124
103
|
end
|
@@ -19,25 +19,29 @@ module IO::Endpoint
|
|
19
19
|
"\#<#{self.class} name=#{nodename.inspect} service=#{service.inspect} family=#{family.inspect} type=#{socktype.inspect} protocol=#{protocol.inspect} flags=#{flags.inspect}>"
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
22
|
+
|
23
|
+
attr :specification
|
25
24
|
|
26
25
|
def hostname
|
27
|
-
@specification
|
26
|
+
@specification[0]
|
27
|
+
end
|
28
|
+
|
29
|
+
def service
|
30
|
+
@specification[1]
|
28
31
|
end
|
29
32
|
|
30
33
|
# Try to connect to the given host by connecting to each address in sequence until a connection is made.
|
31
34
|
# @yield [Socket] the socket which is being connected, may be invoked more than once
|
32
35
|
# @return [Socket] the connected socket
|
33
36
|
# @raise if no connection could complete successfully
|
34
|
-
def connect
|
37
|
+
def connect(wrapper = Wrapper.default, &block)
|
35
38
|
last_error = nil
|
36
39
|
|
37
40
|
Addrinfo.foreach(*@specification) do |address|
|
38
41
|
begin
|
39
|
-
socket =
|
42
|
+
socket = wrapper.connect(address, **@options)
|
40
43
|
rescue Errno::ECONNREFUSED, Errno::ENETUNREACH, Errno::EAGAIN => last_error
|
44
|
+
# Try again unless if possible, otherwise raise...
|
41
45
|
else
|
42
46
|
return socket unless block_given?
|
43
47
|
|
@@ -55,9 +59,9 @@ module IO::Endpoint
|
|
55
59
|
# Invokes the given block for every address which can be bound to.
|
56
60
|
# @yield [Socket] the bound socket
|
57
61
|
# @return [Array<Socket>] an array of bound sockets
|
58
|
-
def bind(&block)
|
62
|
+
def bind(wrapper = Wrapper.default, &block)
|
59
63
|
Addrinfo.foreach(*@specification).map do |address|
|
60
|
-
|
64
|
+
wrapper.bind(address, **@options, &block)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
@@ -71,23 +75,23 @@ module IO::Endpoint
|
|
71
75
|
end
|
72
76
|
end
|
73
77
|
|
74
|
-
# @param
|
78
|
+
# @param arguments nodename, service, family, socktype, protocol, flags. `socktype` will be set to Socket::SOCK_STREAM.
|
75
79
|
# @param options keyword arguments passed on to {HostEndpoint#initialize}
|
76
80
|
#
|
77
81
|
# @return [HostEndpoint]
|
78
|
-
def self.tcp(*
|
79
|
-
|
82
|
+
def self.tcp(*arguments, **options)
|
83
|
+
arguments[3] = ::Socket::SOCK_STREAM
|
80
84
|
|
81
|
-
HostEndpoint.new(
|
85
|
+
HostEndpoint.new(arguments, **options)
|
82
86
|
end
|
83
87
|
|
84
|
-
# @param
|
88
|
+
# @param arguments nodename, service, family, socktype, protocol, flags. `socktype` will be set to Socket::SOCK_DGRAM.
|
85
89
|
# @param options keyword arguments passed on to {HostEndpoint#initialize}
|
86
90
|
#
|
87
91
|
# @return [HostEndpoint]
|
88
|
-
def self.udp(*
|
89
|
-
|
92
|
+
def self.udp(*arguments, **options)
|
93
|
+
arguments[3] = ::Socket::SOCK_DGRAM
|
90
94
|
|
91
|
-
HostEndpoint.new(
|
95
|
+
HostEndpoint.new(arguments, **options)
|
92
96
|
end
|
93
97
|
end
|
@@ -5,13 +5,18 @@
|
|
5
5
|
|
6
6
|
require_relative 'generic'
|
7
7
|
require_relative 'composite_endpoint'
|
8
|
+
require_relative 'socket_endpoint'
|
9
|
+
|
10
|
+
require 'openssl'
|
8
11
|
|
9
12
|
module IO::Endpoint
|
10
13
|
# Pre-connect and pre-bind sockets so that it can be used between processes.
|
11
14
|
class SharedEndpoint < Generic
|
12
15
|
# Create a new `SharedEndpoint` by binding to the given endpoint.
|
13
|
-
def self.bound(endpoint, backlog: Socket::SOMAXCONN, close_on_exec: false)
|
14
|
-
|
16
|
+
def self.bound(endpoint, backlog: Socket::SOMAXCONN, close_on_exec: false, **options)
|
17
|
+
sockets = endpoint.bind(**options)
|
18
|
+
|
19
|
+
sockets.each do |server|
|
15
20
|
# This is somewhat optional. We want to have a generic interface as much as possible so that users of this interface can just call it without knowing a lot of internal details. Therefore, we ignore errors here if it's because the underlying socket does not support the operation.
|
16
21
|
begin
|
17
22
|
server.listen(backlog)
|
@@ -22,7 +27,7 @@ module IO::Endpoint
|
|
22
27
|
server.close_on_exec = close_on_exec
|
23
28
|
end
|
24
29
|
|
25
|
-
return self.new(endpoint,
|
30
|
+
return self.new(endpoint, sockets)
|
26
31
|
end
|
27
32
|
|
28
33
|
# Create a new `SharedEndpoint` by connecting to the given endpoint.
|
@@ -34,18 +39,20 @@ module IO::Endpoint
|
|
34
39
|
return self.new(endpoint, [wrapper])
|
35
40
|
end
|
36
41
|
|
37
|
-
def initialize(endpoint,
|
42
|
+
def initialize(endpoint, sockets, **options)
|
38
43
|
super(**options)
|
39
44
|
|
45
|
+
raise TypeError, "sockets must be an Array" unless sockets.is_a?(Array)
|
46
|
+
|
40
47
|
@endpoint = endpoint
|
41
|
-
@
|
48
|
+
@sockets = sockets
|
42
49
|
end
|
43
50
|
|
44
51
|
attr :endpoint
|
45
|
-
attr :
|
52
|
+
attr :sockets
|
46
53
|
|
47
54
|
def local_address_endpoint(**options)
|
48
|
-
endpoints = @
|
55
|
+
endpoints = @sockets.map do |wrapper|
|
49
56
|
AddressEndpoint.new(wrapper.to_io.local_address)
|
50
57
|
end
|
51
58
|
|
@@ -53,51 +60,77 @@ module IO::Endpoint
|
|
53
60
|
end
|
54
61
|
|
55
62
|
def remote_address_endpoint(**options)
|
56
|
-
endpoints = @
|
63
|
+
endpoints = @sockets.map do |wrapper|
|
57
64
|
AddressEndpoint.new(wrapper.to_io.remote_address)
|
58
65
|
end
|
59
66
|
|
60
67
|
return CompositeEndpoint.new(endpoints, **options)
|
61
68
|
end
|
62
69
|
|
63
|
-
# Close all the internal
|
70
|
+
# Close all the internal sockets.
|
64
71
|
def close
|
65
|
-
@
|
66
|
-
@
|
72
|
+
@sockets.each(&:close)
|
73
|
+
@sockets.clear
|
74
|
+
end
|
75
|
+
|
76
|
+
def each(&block)
|
77
|
+
return to_enum unless block_given?
|
78
|
+
|
79
|
+
@sockets.each do |socket|
|
80
|
+
yield SocketEndpoint.new(socket.dup)
|
81
|
+
end
|
67
82
|
end
|
68
83
|
|
69
|
-
def bind
|
70
|
-
@
|
84
|
+
def bind(wrapper = Wrapper.default, &block)
|
85
|
+
@sockets.each.map do |server|
|
71
86
|
server = server.dup
|
72
87
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
88
|
+
if block_given?
|
89
|
+
wrapper.async do
|
90
|
+
begin
|
91
|
+
yield server
|
92
|
+
ensure
|
93
|
+
server.close
|
94
|
+
end
|
95
|
+
end
|
96
|
+
else
|
97
|
+
server
|
77
98
|
end
|
78
99
|
end
|
79
100
|
end
|
80
101
|
|
81
|
-
def connect
|
82
|
-
@
|
83
|
-
|
102
|
+
def connect(wrapper = Wrapper.default, &block)
|
103
|
+
@sockets.each do |socket|
|
104
|
+
socket = socket.dup
|
105
|
+
|
106
|
+
return socket unless block_given?
|
84
107
|
|
85
108
|
begin
|
86
|
-
yield
|
109
|
+
return yield(socket)
|
87
110
|
ensure
|
88
|
-
|
111
|
+
socket.close
|
89
112
|
end
|
90
113
|
end
|
91
114
|
end
|
92
115
|
|
93
|
-
def accept(
|
116
|
+
def accept(**options, &block)
|
94
117
|
bind do |server|
|
95
|
-
server.
|
118
|
+
server.accept(&block)
|
96
119
|
end
|
97
120
|
end
|
98
121
|
|
99
122
|
def to_s
|
100
|
-
"\#<#{self.class} #{@
|
123
|
+
"\#<#{self.class} #{@sockets.size} descriptors for #{@endpoint}>"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Generic
|
128
|
+
def bound(**options)
|
129
|
+
SharedEndpoint.bound(self, **options)
|
130
|
+
end
|
131
|
+
|
132
|
+
def connected(**options)
|
133
|
+
SharedEndpoint.connected(self, **options)
|
101
134
|
end
|
102
135
|
end
|
103
136
|
end
|
@@ -8,6 +8,38 @@ require_relative 'generic'
|
|
8
8
|
|
9
9
|
require 'openssl'
|
10
10
|
|
11
|
+
module OpenSSL::SSL::SocketForwarder
|
12
|
+
unless method_defined?(:close_on_exec=)
|
13
|
+
def close_on_exec=(value)
|
14
|
+
to_io.close_on_exec = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
unless method_defined?(:close_on_exec)
|
19
|
+
def local_address
|
20
|
+
to_io.local_address
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless method_defined?(:wait)
|
25
|
+
def wait(*arguments)
|
26
|
+
to_io.wait(*arguments)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
unless method_defined?(:wait_readable)
|
31
|
+
def wait_readable(*arguments)
|
32
|
+
to_io.wait_readable(*arguments)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
unless method_defined?(:wait_writable)
|
37
|
+
def wait_writable(*arguments)
|
38
|
+
to_io.wait_writable(*arguments)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
11
43
|
module IO::Endpoint
|
12
44
|
class SSLEndpoint < Generic
|
13
45
|
def initialize(endpoint, **options)
|
@@ -41,13 +73,13 @@ module IO::Endpoint
|
|
41
73
|
@options[:ssl_params]
|
42
74
|
end
|
43
75
|
|
44
|
-
def build_context(context = OpenSSL::SSL::SSLContext.new)
|
76
|
+
def build_context(context = ::OpenSSL::SSL::SSLContext.new)
|
45
77
|
if params = self.params
|
46
78
|
context.set_params(params)
|
47
79
|
end
|
48
80
|
|
49
|
-
context.setup
|
50
|
-
context.freeze
|
81
|
+
# context.setup
|
82
|
+
# context.freeze
|
51
83
|
|
52
84
|
return context
|
53
85
|
end
|
@@ -62,10 +94,12 @@ module IO::Endpoint
|
|
62
94
|
def bind
|
63
95
|
if block_given?
|
64
96
|
@endpoint.bind do |server|
|
65
|
-
yield OpenSSL::SSL::SSLServer.new(server, context)
|
97
|
+
yield ::OpenSSL::SSL::SSLServer.new(server, context)
|
66
98
|
end
|
67
99
|
else
|
68
|
-
|
100
|
+
@endpoint.bind.map do |server|
|
101
|
+
::OpenSSL::SSL::SSLServer.new(server, context)
|
102
|
+
end
|
69
103
|
end
|
70
104
|
end
|
71
105
|
|
@@ -73,7 +107,7 @@ module IO::Endpoint
|
|
73
107
|
# @yield [Socket] the socket which is being connected
|
74
108
|
# @return [Socket] the connected socket
|
75
109
|
def connect(&block)
|
76
|
-
socket = OpenSSL::SSL::SSLSocket.new(@endpoint.connect, context)
|
110
|
+
socket = ::OpenSSL::SSL::SSLSocket.new(@endpoint.connect, context)
|
77
111
|
|
78
112
|
if hostname = self.hostname
|
79
113
|
socket.hostname = hostname
|
@@ -102,22 +136,15 @@ module IO::Endpoint
|
|
102
136
|
yield self.class.new(endpoint, **@options)
|
103
137
|
end
|
104
138
|
end
|
105
|
-
|
106
|
-
protected
|
107
|
-
|
108
|
-
def accepted(socket)
|
109
|
-
socket.accept
|
110
|
-
socket
|
111
|
-
end
|
112
139
|
end
|
113
140
|
|
114
|
-
# @param
|
141
|
+
# @param arguments
|
115
142
|
# @param ssl_context [OpenSSL::SSL::SSLContext, nil]
|
116
143
|
# @param hostname [String, nil]
|
117
144
|
# @param options keyword arguments passed through to {Endpoint.tcp}
|
118
145
|
#
|
119
146
|
# @return [SSLEndpoint]
|
120
|
-
def self.ssl(*
|
121
|
-
SSLEndpoint.new(self.tcp(*
|
147
|
+
def self.ssl(*arguments, ssl_context: nil, hostname: nil, **options)
|
148
|
+
SSLEndpoint.new(self.tcp(*arguments, **options), ssl_context: ssl_context, hostname: hostname)
|
122
149
|
end
|
123
150
|
end
|
@@ -27,14 +27,16 @@ module IO::Endpoint
|
|
27
27
|
end
|
28
28
|
rescue Errno::ECONNREFUSED
|
29
29
|
return false
|
30
|
+
rescue Errno::ENOENT
|
31
|
+
return false
|
30
32
|
end
|
31
33
|
|
32
34
|
def bind(&block)
|
33
35
|
super
|
34
36
|
rescue Errno::EADDRINUSE
|
35
37
|
# 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.
|
36
|
-
if !bound?
|
37
|
-
File.unlink(@path)
|
38
|
+
if !bound?
|
39
|
+
File.unlink(@path) rescue nil
|
38
40
|
retry
|
39
41
|
else
|
40
42
|
raise
|
data/lib/io/endpoint/version.rb
CHANGED
data/lib/io/endpoint/wrapper.rb
CHANGED
@@ -9,16 +9,32 @@ module IO::Endpoint
|
|
9
9
|
class Wrapper
|
10
10
|
include ::Socket::Constants
|
11
11
|
|
12
|
-
if
|
13
|
-
def
|
12
|
+
if IO.method_defined?(:timeout=)
|
13
|
+
def set_timeout(io, timeout)
|
14
14
|
io.timeout = timeout
|
15
15
|
end
|
16
16
|
else
|
17
|
-
def
|
17
|
+
def set_timeout(io, timeout)
|
18
18
|
warn "IO#timeout= not supported on this platform."
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def set_buffered(socket, buffered)
|
23
|
+
case buffered
|
24
|
+
when true
|
25
|
+
socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 0)
|
26
|
+
when false
|
27
|
+
socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
|
28
|
+
end
|
29
|
+
rescue Errno::EINVAL
|
30
|
+
# On Darwin, sometimes occurs when the connection is not yet fully formed. Empirically, TCP_NODELAY is enabled despite this result.
|
31
|
+
rescue Errno::EOPNOTSUPP
|
32
|
+
# Some platforms may simply not support the operation.
|
33
|
+
# Console.logger.warn(self) {"Unable to set sync=#{value}!"}
|
34
|
+
rescue Errno::ENOPROTOOPT
|
35
|
+
# It may not be supported by the protocol (e.g. UDP). ¯\_(ツ)_/¯
|
36
|
+
end
|
37
|
+
|
22
38
|
def async
|
23
39
|
raise NotImplementedError
|
24
40
|
end
|
@@ -26,7 +42,9 @@ module IO::Endpoint
|
|
26
42
|
# Build and wrap the underlying io.
|
27
43
|
# @option reuse_port [Boolean] Allow this port to be bound in multiple processes.
|
28
44
|
# @option reuse_address [Boolean] Allow this port to be bound in multiple processes.
|
29
|
-
|
45
|
+
# @option linger [Boolean] Wait for data to be sent before closing the socket.
|
46
|
+
# @option buffered [Boolean] Enable or disable Nagle's algorithm for TCP sockets.
|
47
|
+
def build(*arguments, timeout: nil, reuse_address: true, reuse_port: nil, linger: nil, buffered: false)
|
30
48
|
socket = ::Socket.new(*arguments)
|
31
49
|
|
32
50
|
# Set the timeout:
|
@@ -43,7 +61,11 @@ module IO::Endpoint
|
|
43
61
|
end
|
44
62
|
|
45
63
|
if linger
|
46
|
-
socket.setsockopt(SOL_SOCKET, SO_LINGER,
|
64
|
+
socket.setsockopt(SOL_SOCKET, SO_LINGER, 1)
|
65
|
+
end
|
66
|
+
|
67
|
+
if buffered == false
|
68
|
+
set_buffered(socket, buffered)
|
47
69
|
end
|
48
70
|
|
49
71
|
yield socket if block_given?
|
@@ -51,6 +73,7 @@ module IO::Endpoint
|
|
51
73
|
return socket
|
52
74
|
rescue
|
53
75
|
socket&.close
|
76
|
+
raise
|
54
77
|
end
|
55
78
|
|
56
79
|
# Establish a connection to a given `remote_address`.
|
data/readme.md
CHANGED
@@ -18,6 +18,14 @@ We welcome contributions to this project.
|
|
18
18
|
4. Push to the branch (`git push origin my-new-feature`).
|
19
19
|
5. Create new Pull Request.
|
20
20
|
|
21
|
+
### Developer Certificate of Origin
|
22
|
+
|
23
|
+
This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted.
|
24
|
+
|
25
|
+
### Contributor Covenant
|
26
|
+
|
27
|
+
This project is governed by the [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms.
|
28
|
+
|
21
29
|
## See Also
|
22
30
|
|
23
31
|
- [async-io](https://github.com/socketry/async-io) — Asynchronous IO primitives.
|
data.tar.gz.sig
CHANGED
@@ -1 +1,3 @@
|
|
1
|
-
|
1
|
+
(Z\��Q���^�;^Ȍ$���+��X� �t�e*9��rKg3�7�c$=]���z+��a�lt��X��^bM�G3���ma�ew����d��(#���v+e��B��K6�+��>|9��~��*^o[GM�1UT5Sv|"0
|
2
|
+
�>���$i3���R�\��ziބg��-"�5,��E%�3n�p��3�;�a� ���9��|G��K֥ܺ�/���8@)]������9
|
3
|
+
���^5Am��I����. ͈B�$^.�/8bH�r`�sYe@�&Xj���ku���M�.=��^�Bڗ=Ʋ�)�������4�֑f��eﶔ��c33r��~�|�W
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-endpoint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -37,50 +37,8 @@ cert_chain:
|
|
37
37
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
38
38
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
39
39
|
-----END CERTIFICATE-----
|
40
|
-
date: 2023-
|
41
|
-
dependencies:
|
42
|
-
- !ruby/object:Gem::Dependency
|
43
|
-
name: bake
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - ">="
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '0'
|
49
|
-
type: :development
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: '0'
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: covered
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: sus
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
40
|
+
date: 2023-12-28 00:00:00.000000000 Z
|
41
|
+
dependencies: []
|
84
42
|
description:
|
85
43
|
email:
|
86
44
|
executables: []
|
@@ -120,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
78
|
- !ruby/object:Gem::Version
|
121
79
|
version: '0'
|
122
80
|
requirements: []
|
123
|
-
rubygems_version: 3.
|
81
|
+
rubygems_version: 3.5.3
|
124
82
|
signing_key:
|
125
83
|
specification_version: 4
|
126
84
|
summary: Provides a separation of concerns interface for IO endpoints.
|
metadata.gz.sig
CHANGED
Binary file
|