io-endpoint 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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�|�