io-endpoint 0.13.1 → 0.15.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: 80426a4ee162f18eb945d9ce2fd75bde3cf23e9d5bb8333faa2ff627f6b87a23
4
- data.tar.gz: 37d79a722c7371c993476fc3061d5c63e7c10f6051dcdc5215d079bac88d5965
3
+ metadata.gz: 85f53ad778e7ab62a17def218d84235d361df69805fa9f0edbf08b4ec0dfebc1
4
+ data.tar.gz: db08fed38c6ff791c0d4b98af3a661af718c5c44595f135cb0bf77147a36155b
5
5
  SHA512:
6
- metadata.gz: b89867de53a90531d5b9f1484d529e3f556b6ac75b30b6174c2bfc7f3c0199b80208b7699f6998d8c61b8e0eef666b72f66e10377090b566ae4058b4d229859d
7
- data.tar.gz: a7c98d22e20fd3cdd558b8266b92bfb88fc110c6f0a144769daf58b505447cc0e0fff04a4b07d0bbe490327a3a46d5f7b353f436cb72651040cae8e350523f54
6
+ metadata.gz: 7c00c73e293110af0cb9caed8e7a8477b1c18eabe896b523297e42f3daf689586e916c989e103c33b9d4be37ce75e67a3433d2bfed92cdd5e366177076454bfe
7
+ data.tar.gz: a1bb99c8199618a8984deca2678c9884f382542b38c83c3fe6a08b1896a13fd5f9a57efb125b487a259f9b0a0e6fc4425446aea083ce8423b27acc1420178331
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023, by Samuel Williams.
4
+ # Copyright, 2023-2025, by Samuel Williams.
5
5
 
6
- require 'socket'
6
+ require "socket"
7
7
 
8
- require_relative 'generic'
9
- require_relative 'wrapper'
8
+ require_relative "generic"
9
+ require_relative "wrapper"
10
10
 
11
11
  module IO::Endpoint
12
12
  class AddressEndpoint < Generic
@@ -17,6 +17,17 @@ module IO::Endpoint
17
17
  end
18
18
 
19
19
  def to_s
20
+ case @address.afamily
21
+ when Socket::AF_INET
22
+ "inet:#{@address.inspect_sockaddr}"
23
+ when Socket::AF_INET6
24
+ "inet6:#{@address.inspect_sockaddr}"
25
+ else
26
+ "address:#{@address.inspect_sockaddr}"
27
+ end
28
+ end
29
+
30
+ def inspect
20
31
  "\#<#{self.class} address=#{@address.inspect}>"
21
32
  end
22
33
 
@@ -26,13 +37,13 @@ module IO::Endpoint
26
37
  # @yield {|socket| ...} An optional block which will be passed the socket.
27
38
  # @parameter socket [Socket] The socket which has been bound.
28
39
  # @return [Array(Socket)] the bound socket
29
- def bind(wrapper = Wrapper.default, &block)
40
+ def bind(wrapper = self.wrapper, &block)
30
41
  [wrapper.bind(@address, **@options, &block)]
31
42
  end
32
43
 
33
44
  # Connects a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
34
45
  # @return [Socket] the connected socket
35
- def connect(wrapper = Wrapper.default, &block)
46
+ def connect(wrapper = self.wrapper, &block)
36
47
  wrapper.connect(@address, **@options, &block)
37
48
  end
38
49
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2024, by Samuel Williams.
4
+ # Copyright, 2024-2025, by Samuel Williams.
5
5
 
6
- require_relative 'generic'
7
- require_relative 'composite_endpoint'
8
- require_relative 'address_endpoint'
6
+ require_relative "generic"
7
+ require_relative "composite_endpoint"
8
+ require_relative "address_endpoint"
9
9
 
10
10
  module IO::Endpoint
11
11
  class BoundEndpoint < Generic
@@ -55,13 +55,17 @@ module IO::Endpoint
55
55
  end
56
56
 
57
57
  def to_s
58
+ "bound:#{@endpoint}"
59
+ end
60
+
61
+ def inspect
58
62
  "\#<#{self.class} #{@sockets.size} bound sockets for #{@endpoint}>"
59
63
  end
60
64
 
61
- def bind(wrapper = Wrapper.default, &block)
65
+ def bind(wrapper = self.wrapper, &block)
62
66
  @sockets.map do |server|
63
67
  if block_given?
64
- wrapper.async do
68
+ wrapper.schedule do
65
69
  yield server
66
70
  end
67
71
  else
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023-2024, by Samuel Williams.
4
+ # Copyright, 2023-2025, by Samuel Williams.
5
5
 
6
- require_relative 'generic'
6
+ require_relative "generic"
7
7
 
8
8
  module IO::Endpoint
9
9
  # A composite endpoint is a collection of endpoints that are used in order.
@@ -19,6 +19,14 @@ module IO::Endpoint
19
19
  @endpoints = endpoints
20
20
  end
21
21
 
22
+ def to_s
23
+ "composite:#{@endpoints.join(",")}"
24
+ end
25
+
26
+ def inspect
27
+ "\#<#{self.class} endpoints=#{@endpoints}>"
28
+ end
29
+
22
30
  def with(**options)
23
31
  self.class.new(endpoints.map{|endpoint| endpoint.with(**options)}, **@options.merge(options))
24
32
  end
@@ -36,7 +44,7 @@ module IO::Endpoint
36
44
  end
37
45
  end
38
46
 
39
- def connect(wrapper = Wrapper.default, &block)
47
+ def connect(wrapper = self.wrapper, &block)
40
48
  last_error = nil
41
49
 
42
50
  @endpoints.each do |endpoint|
@@ -49,7 +57,7 @@ module IO::Endpoint
49
57
  raise last_error
50
58
  end
51
59
 
52
- def bind(wrapper = Wrapper.default, &block)
60
+ def bind(wrapper = self.wrapper, &block)
53
61
  if block_given?
54
62
  @endpoints.each do |endpoint|
55
63
  endpoint.bind(&block)
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2024, by Samuel Williams.
4
+ # Copyright, 2024-2025, by Samuel Williams.
5
5
 
6
- require_relative 'generic'
7
- require_relative 'composite_endpoint'
8
- require_relative 'socket_endpoint'
6
+ require_relative "generic"
7
+ require_relative "composite_endpoint"
8
+ require_relative "socket_endpoint"
9
9
 
10
- require 'openssl'
10
+ require "openssl"
11
11
 
12
12
  module IO::Endpoint
13
13
  class ConnectedEndpoint < Generic
@@ -41,7 +41,7 @@ module IO::Endpoint
41
41
  AddressEndpoint.new(socket.to_io.remote_address, **options)
42
42
  end
43
43
 
44
- def connect(wrapper = Wrapper.default, &block)
44
+ def connect(wrapper = self.wrapper, &block)
45
45
  if block_given?
46
46
  yield @socket
47
47
  else
@@ -57,6 +57,10 @@ module IO::Endpoint
57
57
  end
58
58
 
59
59
  def to_s
60
+ "connected:#{@endpoint}"
61
+ end
62
+
63
+ def inspect
60
64
  "\#<#{self.class} #{@socket} connected for #{@endpoint}>"
61
65
  end
62
66
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023-2024, by Samuel Williams.
4
+ # Copyright, 2023-2025, by Samuel Williams.
5
5
 
6
6
  # require_relative 'address'
7
- require 'uri'
8
- require 'socket'
7
+ require "uri"
8
+ require "socket"
9
9
 
10
10
  module IO::Endpoint
11
11
  Address = Addrinfo
@@ -64,21 +64,21 @@ module IO::Endpoint
64
64
  # @yields {|socket| ...} An optional block which will be passed the socket.
65
65
  # @parameter socket [Socket] The socket which has been bound.
66
66
  # @returns [Array(Socket)] the bound socket
67
- def bind(wrapper = Wrapper.default, &block)
67
+ def bind(wrapper = self.wrapper, &block)
68
68
  raise NotImplementedError
69
69
  end
70
70
 
71
71
  # Connects a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
72
72
  # @parameter wrapper [Wrapper] The wrapper to use for connecting.
73
73
  # @return [Socket] the connected socket
74
- def connect(wrapper = Wrapper.default, &block)
74
+ def connect(wrapper = self.wrapper, &block)
75
75
  raise NotImplementedError
76
76
  end
77
77
 
78
78
  # Bind and accept connections on the given address.
79
79
  # @parameter wrapper [Wrapper] The wrapper to use for accepting connections.
80
80
  # @yields [Socket] The accepted socket.
81
- def accept(wrapper = Wrapper.default, &block)
81
+ def accept(wrapper = self.wrapper, &block)
82
82
  bind(wrapper) do |server|
83
83
  wrapper.accept(server, **@options, &block)
84
84
  end
@@ -109,5 +109,10 @@ module IO::Endpoint
109
109
 
110
110
  IO::Endpoint.public_send(uri.scheme, uri.host, uri.port, **options)
111
111
  end
112
+
113
+ # The default wrapper to use for binding, connecting, and accepting connections.
114
+ def wrapper
115
+ @options[:wrapper] || Wrapper.default
116
+ end
112
117
  end
113
118
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023, by Samuel Williams.
4
+ # Copyright, 2023-2025, by Samuel Williams.
5
5
 
6
- require_relative 'address_endpoint'
6
+ require_relative "address_endpoint"
7
7
 
8
8
  module IO::Endpoint
9
9
  class HostEndpoint < Generic
@@ -14,6 +14,10 @@ module IO::Endpoint
14
14
  end
15
15
 
16
16
  def to_s
17
+ "host:#{@specification[0]}:#{@specification[1]}"
18
+ end
19
+
20
+ def inspect
17
21
  nodename, service, family, socktype, protocol, flags = @specification
18
22
 
19
23
  "\#<#{self.class} name=#{nodename.inspect} service=#{service.inspect} family=#{family.inspect} type=#{socktype.inspect} protocol=#{protocol.inspect} flags=#{flags.inspect}>"
@@ -34,7 +38,7 @@ module IO::Endpoint
34
38
  # @yield [Socket] the socket which is being connected, may be invoked more than once
35
39
  # @return [Socket] the connected socket
36
40
  # @raise if no connection could complete successfully
37
- def connect(wrapper = Wrapper.default, &block)
41
+ def connect(wrapper = self.wrapper, &block)
38
42
  last_error = nil
39
43
 
40
44
  Addrinfo.foreach(*@specification) do |address|
@@ -59,7 +63,7 @@ module IO::Endpoint
59
63
  # Invokes the given block for every address which can be bound to.
60
64
  # @yield [Socket] the bound socket
61
65
  # @return [Array<Socket>] an array of bound sockets
62
- def bind(wrapper = Wrapper.default, &block)
66
+ def bind(wrapper = self.wrapper, &block)
63
67
  Addrinfo.foreach(*@specification).map do |address|
64
68
  wrapper.bind(address, **@options, &block)
65
69
  end
@@ -3,5 +3,5 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2023-2024, by Samuel Williams.
5
5
 
6
- require_relative 'bound_endpoint'
7
- require_relative 'connected_endpoint'
6
+ require_relative "bound_endpoint"
7
+ require_relative "connected_endpoint"
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023, by Samuel Williams.
4
+ # Copyright, 2023-2024, by Samuel Williams.
5
5
 
6
- require_relative 'generic'
6
+ require_relative "generic"
7
7
 
8
8
  module IO::Endpoint
9
9
  # This class doesn't exert ownership over the specified socket, wraps a native ::IO.
@@ -15,6 +15,10 @@ module IO::Endpoint
15
15
  end
16
16
 
17
17
  def to_s
18
+ "socket:#{@socket}"
19
+ end
20
+
21
+ def inspect
18
22
  "\#<#{self.class} #{@socket.inspect}>"
19
23
  end
20
24
 
@@ -3,10 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2023-2024, by Samuel Williams.
5
5
 
6
- require_relative 'host_endpoint'
7
- require_relative 'generic'
6
+ require_relative "host_endpoint"
7
+ require_relative "generic"
8
8
 
9
- require 'openssl'
9
+ require "openssl"
10
10
 
11
11
  module OpenSSL
12
12
  module SSL
@@ -87,7 +87,11 @@ module IO::Endpoint
87
87
  end
88
88
 
89
89
  def to_s
90
- "\#<#{self.class} #{@endpoint}>"
90
+ "ssl:#{@endpoint}"
91
+ end
92
+
93
+ def inspect
94
+ "\#<#{self.class} endpoint=#{@endpoint.inspect}>"
91
95
  end
92
96
 
93
97
  def address
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023, by Samuel Williams.
4
+ # Copyright, 2023-2024, by Samuel Williams.
5
5
 
6
- require_relative 'address_endpoint'
6
+ require_relative "address_endpoint"
7
7
 
8
8
  module IO::Endpoint
9
9
  # This class doesn't exert ownership over the specified unix socket and ensures exclusive access by using `flock` where possible.
@@ -16,7 +16,11 @@ module IO::Endpoint
16
16
  end
17
17
 
18
18
  def to_s
19
- "\#<#{self.class} #{@path.inspect}>"
19
+ "unix:#{@path}"
20
+ end
21
+
22
+ def inspect
23
+ "\#<#{self.class} path=#{@path.inspect}>"
20
24
  end
21
25
 
22
26
  attr :path
@@ -5,6 +5,6 @@
5
5
 
6
6
  class IO
7
7
  module Endpoint
8
- VERSION = "0.13.1"
8
+ VERSION = "0.15.0"
9
9
  end
10
10
  end
@@ -1,14 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023-2024, by Samuel Williams.
4
+ # Copyright, 2023-2025, by Samuel Williams.
5
5
 
6
- require 'socket'
6
+ require "socket"
7
7
 
8
8
  module IO::Endpoint
9
9
  class Wrapper
10
10
  include ::Socket::Constants
11
11
 
12
+ if Fiber.respond_to?(:scheduler)
13
+ def schedule(&block)
14
+ if Fiber.scheduler
15
+ Fiber.schedule(&block)
16
+ else
17
+ Thread.new(&block)
18
+ end
19
+ end
20
+ else
21
+ def schedule(&block)
22
+ Thread.new(&block)
23
+ end
24
+ end
25
+
12
26
  def set_timeout(io, timeout)
13
27
  if io.respond_to?(:timeout=)
14
28
  io.timeout = timeout
@@ -30,8 +44,13 @@ module IO::Endpoint
30
44
  # It may not be supported by the protocol (e.g. UDP). ¯\_(ツ)_/¯
31
45
  end
32
46
 
33
- def async
34
- raise NotImplementedError
47
+ # Connect a socket to a remote address.
48
+ # This is an extension point for subclasses to provide additional functionality.
49
+ #
50
+ # @parameter socket [Socket] The socket to connect.
51
+ # @parameter remote_address [Address] The remote address to connect to.
52
+ def socket_connect(socket, remote_address)
53
+ socket.connect(remote_address.to_sockaddr)
35
54
  end
36
55
 
37
56
  # Establish a connection to a given `remote_address`.
@@ -72,7 +91,7 @@ module IO::Endpoint
72
91
  end
73
92
 
74
93
  begin
75
- socket.connect(remote_address.to_sockaddr)
94
+ socket_connect(socket, remote_address)
76
95
  rescue Exception
77
96
  socket.close
78
97
  raise
@@ -142,7 +161,7 @@ module IO::Endpoint
142
161
 
143
162
  return socket unless block_given?
144
163
 
145
- async do
164
+ schedule do
146
165
  begin
147
166
  yield socket
148
167
  ensure
@@ -151,11 +170,21 @@ module IO::Endpoint
151
170
  end
152
171
  end
153
172
 
173
+ # Accept a connection from a bound socket.
174
+ # This is an extension point for subclasses to provide additional functionality.
175
+ #
176
+ # @parameter server [Socket] The bound server socket.
177
+ # @returns [Tuple(Socket, Address)] The connected socket and the remote address.
178
+ def socket_accept(server)
179
+ server.accept
180
+ end
181
+
154
182
  # Bind to a local address and accept connections in a loop.
155
183
  def accept(server, timeout: nil, linger: nil, **options, &block)
156
184
  # Ensure we use a `loop do ... end` so that state is not leaked between iterations:
185
+
157
186
  loop do
158
- socket, address = server.accept
187
+ socket, address = socket_accept(server)
159
188
 
160
189
  if linger
161
190
  socket.setsockopt(SOL_SOCKET, SO_LINGER, 1)
@@ -165,7 +194,7 @@ module IO::Endpoint
165
194
  set_timeout(socket, timeout)
166
195
  end
167
196
 
168
- async do
197
+ schedule do
169
198
  # Some sockets, notably SSL sockets, need application level negotiation before they are ready:
170
199
  if socket.respond_to?(:start)
171
200
  begin
@@ -183,31 +212,11 @@ module IO::Endpoint
183
212
  end
184
213
  end
185
214
  end
186
- end
187
-
188
- class ThreadWrapper < Wrapper
189
- def async(&block)
190
- ::Thread.new(&block)
191
- end
192
- end
193
-
194
- class FiberWrapper < Wrapper
195
- def async(&block)
196
- ::Fiber.schedule(&block)
197
- end
198
- end
199
-
200
- if Fiber.respond_to?(:scheduler)
201
- def Wrapper.default
202
- if Fiber.scheduler
203
- FiberWrapper.new
204
- else
205
- ThreadWrapper.new
206
- end
207
- end
208
- else
209
- def Wrapper.default
210
- ThreadWrapper.new
215
+
216
+ DEFAULT = new
217
+
218
+ def self.default
219
+ DEFAULT
211
220
  end
212
221
  end
213
222
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2023-2024, by Samuel Williams.
3
+ Copyright, 2023-2025, by Samuel Williams.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,11 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-endpoint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain:
11
10
  - |
@@ -37,10 +36,8 @@ cert_chain:
37
36
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
38
37
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
39
38
  -----END CERTIFICATE-----
40
- date: 2024-08-27 00:00:00.000000000 Z
39
+ date: 2025-02-11 00:00:00.000000000 Z
41
40
  dependencies: []
42
- description:
43
- email:
44
41
  executables: []
45
42
  extensions: []
46
43
  extra_rdoc_files: []
@@ -66,7 +63,6 @@ licenses:
66
63
  metadata:
67
64
  documentation_uri: https://socketry.github.io/io-endpoint
68
65
  source_code_uri: https://github.com/socketry/io-endpoint.git
69
- post_install_message:
70
66
  rdoc_options: []
71
67
  require_paths:
72
68
  - lib
@@ -81,8 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
77
  - !ruby/object:Gem::Version
82
78
  version: '0'
83
79
  requirements: []
84
- rubygems_version: 3.5.11
85
- signing_key:
80
+ rubygems_version: 3.6.2
86
81
  specification_version: 4
87
82
  summary: Provides a separation of concerns interface for IO endpoints.
88
83
  test_files: []
metadata.gz.sig CHANGED
@@ -1,6 +1,5 @@
1
- ^-a�pы }x�7�!ipn�K��h��EWl}�Ă��ソ]) �?��n)3�[��x�,ό��|�1�K���9�S-F��g BZ�<�Oթ Rj{�:���\��ZC>6S��K_�}6_��$G�`���~bp,*���$
2
- ��ix��`}r����]M���S i� 7<����
3
-
4
- ��%�^��47��{��ptl$��t���-=&YU&��ҁ��av���I�i4s
5
- >)����cC�٣Ŧ���{:-N.K#
6
- ������2Dz^
1
+ ��UP���8fp& ��f�޻����Y'mH���"wN1é�GL��Ǻ��nUoe>�
2
+
3
+ m\oXkAl&�,x���2��x��7�qx��À��
4
+ ��ݯ"d�B�3O�=.
5
+ ���;b�-���z\%VK8��6�y}~od$g�S���y0If%G�Ȭ�i1Jd�!J/S��ڲg��3�x5�uڔQ0E���J`�k�����ҥ���0���#�ʃ3�N?$�Y�3Ml���[UG�6��@1��жT`�t��3{I���ZAUz?1j3�Mh/�\O.�@��.�q�3���Qf�|Iޔ6E�uӸ������}��_R��o�H� f\b�\p��7ʰ� %�n�uN���Y�J]I�h�b�!���9�|�