io-endpoint 0.14.0 → 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: 0f51510c717c48af4dbb57bdc410ba223ca4bb5f7880c57ca37e8a95c33a1c59
4
- data.tar.gz: 1175cb1f51a2e242a87f3d807047ca01b4f42d06842d5162459cc9f8566eb196
3
+ metadata.gz: 85f53ad778e7ab62a17def218d84235d361df69805fa9f0edbf08b4ec0dfebc1
4
+ data.tar.gz: db08fed38c6ff791c0d4b98af3a661af718c5c44595f135cb0bf77147a36155b
5
5
  SHA512:
6
- metadata.gz: 616c3bc275c978686816bc6dbcfb5100101bea253e393693d7f319fca284b41955b58d59d2091cf2cc6f0f00bfbdf00b2b1ad8d04346d91f2af8a70f55817070
7
- data.tar.gz: 1e9b8a3e7e1d1379a270f92fef0075b938a708f7744f622e9c14ab5cb6e179e7e0ea465e03b9ce49eeec88bb9f2aeca126b397c92d0f7f4e378512a8327ce5ef
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
@@ -37,13 +37,13 @@ module IO::Endpoint
37
37
  # @yield {|socket| ...} An optional block which will be passed the socket.
38
38
  # @parameter socket [Socket] The socket which has been bound.
39
39
  # @return [Array(Socket)] the bound socket
40
- def bind(wrapper = Wrapper.default, &block)
40
+ def bind(wrapper = self.wrapper, &block)
41
41
  [wrapper.bind(@address, **@options, &block)]
42
42
  end
43
43
 
44
44
  # Connects a socket to the given address. If a block is given, the socket will be automatically closed when the block exits.
45
45
  # @return [Socket] the connected socket
46
- def connect(wrapper = Wrapper.default, &block)
46
+ def connect(wrapper = self.wrapper, &block)
47
47
  wrapper.connect(@address, **@options, &block)
48
48
  end
49
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
@@ -62,10 +62,10 @@ module IO::Endpoint
62
62
  "\#<#{self.class} #{@sockets.size} bound sockets for #{@endpoint}>"
63
63
  end
64
64
 
65
- def bind(wrapper = Wrapper.default, &block)
65
+ def bind(wrapper = self.wrapper, &block)
66
66
  @sockets.map do |server|
67
67
  if block_given?
68
- wrapper.async do
68
+ wrapper.schedule do
69
69
  yield server
70
70
  end
71
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.
@@ -44,7 +44,7 @@ module IO::Endpoint
44
44
  end
45
45
  end
46
46
 
47
- def connect(wrapper = Wrapper.default, &block)
47
+ def connect(wrapper = self.wrapper, &block)
48
48
  last_error = nil
49
49
 
50
50
  @endpoints.each do |endpoint|
@@ -57,7 +57,7 @@ module IO::Endpoint
57
57
  raise last_error
58
58
  end
59
59
 
60
- def bind(wrapper = Wrapper.default, &block)
60
+ def bind(wrapper = self.wrapper, &block)
61
61
  if block_given?
62
62
  @endpoints.each do |endpoint|
63
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
@@ -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
@@ -38,7 +38,7 @@ module IO::Endpoint
38
38
  # @yield [Socket] the socket which is being connected, may be invoked more than once
39
39
  # @return [Socket] the connected socket
40
40
  # @raise if no connection could complete successfully
41
- def connect(wrapper = Wrapper.default, &block)
41
+ def connect(wrapper = self.wrapper, &block)
42
42
  last_error = nil
43
43
 
44
44
  Addrinfo.foreach(*@specification) do |address|
@@ -63,7 +63,7 @@ module IO::Endpoint
63
63
  # Invokes the given block for every address which can be bound to.
64
64
  # @yield [Socket] the bound socket
65
65
  # @return [Array<Socket>] an array of bound sockets
66
- def bind(wrapper = Wrapper.default, &block)
66
+ def bind(wrapper = self.wrapper, &block)
67
67
  Addrinfo.foreach(*@specification).map do |address|
68
68
  wrapper.bind(address, **@options, &block)
69
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.
@@ -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
@@ -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.
@@ -5,6 +5,6 @@
5
5
 
6
6
  class IO
7
7
  module Endpoint
8
- VERSION = "0.14.0"
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.14.0
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-10-12 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,2 +1,5 @@
1
- ^�cC��|��Ta]}e@�y�! �M��!��"y%�s��M1LWDk�&���X���N
2
- Q0./���I�>�r߯{�{n֧�.)P����FM7+�N9�����J[�Rk;+�R�Qru�Z~�"[_at� !�Q�>�lFi��އ4�L� }� �,��L"Y�L|/
1
+ ��UP���8fp& ��f�޻����Y'mH���"wN1é�GL��Ǻ��nUoe>�
2
+
3
+ m\oXk�Al&�,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�|�