io-endpoint 0.14.0 → 0.15.1

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: 52e4f0d4b8e0e46f2ad47c655f0b841fd9cbd4b26165139a5260546f5baa5167
4
+ data.tar.gz: a86e657651e34a15f300d67e1df05b7ef29b6e5624b61c2bc06df57269f005dd
5
5
  SHA512:
6
- metadata.gz: 616c3bc275c978686816bc6dbcfb5100101bea253e393693d7f319fca284b41955b58d59d2091cf2cc6f0f00bfbdf00b2b1ad8d04346d91f2af8a70f55817070
7
- data.tar.gz: 1e9b8a3e7e1d1379a270f92fef0075b938a708f7744f622e9c14ab5cb6e179e7e0ea465e03b9ce49eeec88bb9f2aeca126b397c92d0f7f4e378512a8327ce5ef
6
+ metadata.gz: b33453871ae938df8dc7c21bf5eb2db870a7433ec61015dc3aa0b1f1f572ff36f3bd46c3f447e53ee58891c4570215bcf14c8c06010433d6dcaf1956b7034659
7
+ data.tar.gz: 8a1143e06da6a04216f6e7a5a9af31530b3867e89771e739e28e67d68987dbb9be7e587bba86cfd934f7e80f85043f4cbfb10119dd11521bac4747d70708e840
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.1"
9
9
  end
10
10
  end
@@ -1,14 +1,33 @@
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
+
26
+ # Legacy method for compatibility with older code.
27
+ def async(&block)
28
+ schedule(&block)
29
+ end
30
+
12
31
  def set_timeout(io, timeout)
13
32
  if io.respond_to?(:timeout=)
14
33
  io.timeout = timeout
@@ -30,8 +49,13 @@ module IO::Endpoint
30
49
  # It may not be supported by the protocol (e.g. UDP). ¯\_(ツ)_/¯
31
50
  end
32
51
 
33
- def async
34
- raise NotImplementedError
52
+ # Connect a socket to a remote address.
53
+ # This is an extension point for subclasses to provide additional functionality.
54
+ #
55
+ # @parameter socket [Socket] The socket to connect.
56
+ # @parameter remote_address [Address] The remote address to connect to.
57
+ def socket_connect(socket, remote_address)
58
+ socket.connect(remote_address.to_sockaddr)
35
59
  end
36
60
 
37
61
  # Establish a connection to a given `remote_address`.
@@ -72,7 +96,7 @@ module IO::Endpoint
72
96
  end
73
97
 
74
98
  begin
75
- socket.connect(remote_address.to_sockaddr)
99
+ socket_connect(socket, remote_address)
76
100
  rescue Exception
77
101
  socket.close
78
102
  raise
@@ -142,7 +166,7 @@ module IO::Endpoint
142
166
 
143
167
  return socket unless block_given?
144
168
 
145
- async do
169
+ schedule do
146
170
  begin
147
171
  yield socket
148
172
  ensure
@@ -151,11 +175,21 @@ module IO::Endpoint
151
175
  end
152
176
  end
153
177
 
178
+ # Accept a connection from a bound socket.
179
+ # This is an extension point for subclasses to provide additional functionality.
180
+ #
181
+ # @parameter server [Socket] The bound server socket.
182
+ # @returns [Tuple(Socket, Address)] The connected socket and the remote address.
183
+ def socket_accept(server)
184
+ server.accept
185
+ end
186
+
154
187
  # Bind to a local address and accept connections in a loop.
155
188
  def accept(server, timeout: nil, linger: nil, **options, &block)
156
189
  # Ensure we use a `loop do ... end` so that state is not leaked between iterations:
190
+
157
191
  loop do
158
- socket, address = server.accept
192
+ socket, address = socket_accept(server)
159
193
 
160
194
  if linger
161
195
  socket.setsockopt(SOL_SOCKET, SO_LINGER, 1)
@@ -165,7 +199,7 @@ module IO::Endpoint
165
199
  set_timeout(socket, timeout)
166
200
  end
167
201
 
168
- async do
202
+ schedule do
169
203
  # Some sockets, notably SSL sockets, need application level negotiation before they are ready:
170
204
  if socket.respond_to?(:start)
171
205
  begin
@@ -183,31 +217,11 @@ module IO::Endpoint
183
217
  end
184
218
  end
185
219
  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
220
+
221
+ DEFAULT = new
222
+
223
+ def self.default
224
+ DEFAULT
211
225
  end
212
226
  end
213
227
  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.1
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-13 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,4 @@
1
- ^�cC��|��Ta]}�e@�y�!M��!��"y%�s��M1LWDk�&���X���N
2
- Q0./���I�>�r߯{�{n֧�.)P����FM7+�N9�����J[�Rk;+�R�Qr�u�Z~�"[_at� !�Q�>�lFi��އ4�L� }� �,��L"Y�L|/
1
+ m�����h9tq]G�d���o}�W L,P��\d���N@��x\"���gx":M8 �����zar)��:�݊�˕�Hh{B�Z[�].l���*�5�&�s4bA���c�����=�1�m����x�a�z2�l%n��P�ջOčpmL���6����
2
+ @@���Nۏ��ܐ�Q}r���
3
+ �幊c��@ �\ �G6�����ޢ
4
+ �H�Y �ߍV��(�֑����R�R�4坼�