io-endpoint 0.17.1 → 0.17.2
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 +3 -1
- data/lib/io/endpoint/host_endpoint.rb +1 -2
- data/lib/io/endpoint/unix_endpoint.rb +92 -8
- data/lib/io/endpoint/version.rb +2 -2
- data/lib/io/endpoint.rb +1 -1
- data/license.md +1 -0
- data/readme.md +4 -4
- data/releases.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +2 -1
- 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: af9622a36778938631f679dda8abc06668454c5693551761173757b2df01ec76
|
|
4
|
+
data.tar.gz: e3d58e00ad0e067628d53d7950fd4a801a588fe7935e53f74d0bdc3e5f810e8a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a341c62ee7a064bc18cdecb7fcfc08cc40b2a9f863baf12b0423d8389af1c0cf90b21025d78b4dce04e7abe3007f2c32ef0e0bb6f46bc9cecaee620d1e29a967
|
|
7
|
+
data.tar.gz: f1abb49094a40133a3861d55a58be3efb2d868ad40cddf27b33a080e4596a872f422e7a2c70cca0ead57ebff47b193c5b823ef55c7cd8cac5fd5c855ae9749a1
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2023-
|
|
4
|
+
# Copyright, 2023-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "socket"
|
|
7
7
|
|
|
@@ -28,6 +28,8 @@ module IO::Endpoint
|
|
|
28
28
|
"inet:#{@address.inspect_sockaddr}"
|
|
29
29
|
when Socket::AF_INET6
|
|
30
30
|
"inet6:#{@address.inspect_sockaddr}"
|
|
31
|
+
when Socket::AF_UNIX
|
|
32
|
+
"unix:#{@address.unix_path}"
|
|
31
33
|
else
|
|
32
34
|
"address:#{@address.inspect_sockaddr}"
|
|
33
35
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2023-
|
|
4
|
+
# Copyright, 2023-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "address_endpoint"
|
|
7
7
|
|
|
@@ -31,7 +31,6 @@ module IO::Endpoint
|
|
|
31
31
|
"\#<#{self.class} name=#{nodename.inspect} service=#{service.inspect} family=#{family.inspect} type=#{socktype.inspect} protocol=#{protocol.inspect} flags=#{flags.inspect}>"
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
# @attribute [Array] The host specification array.
|
|
36
35
|
attr :specification
|
|
37
36
|
|
|
@@ -1,22 +1,44 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2023-
|
|
4
|
+
# Copyright, 2023-2026, by Samuel Williams.
|
|
5
|
+
# Copyright, 2026, by Delton Ding.
|
|
6
|
+
|
|
7
|
+
require "digest"
|
|
8
|
+
require "fileutils"
|
|
9
|
+
require "tmpdir"
|
|
5
10
|
|
|
6
11
|
require_relative "address_endpoint"
|
|
7
12
|
|
|
8
13
|
module IO::Endpoint
|
|
9
14
|
# This class doesn't exert ownership over the specified unix socket and ensures exclusive access by using `flock` where possible.
|
|
10
15
|
class UNIXEndpoint < AddressEndpoint
|
|
16
|
+
# Compute a stable temporary UNIX socket path for an overlong path.
|
|
17
|
+
# @parameter path [String] The original (possibly overlong) path.
|
|
18
|
+
# @returns [String] A short, stable path suitable for {Address.unix}.
|
|
19
|
+
def self.short_path_for(path)
|
|
20
|
+
# We need to ensure the path is absolute and canonical, otherwise the SHA1 hash will not be consistent:
|
|
21
|
+
path = File.expand_path(path)
|
|
22
|
+
|
|
23
|
+
# We then use the SHA1 hash of the path to create a short, stable path:
|
|
24
|
+
File.join(Dir.tmpdir, Digest::SHA1.hexdigest(path) + ".ipc")
|
|
25
|
+
end
|
|
26
|
+
|
|
11
27
|
# Initialize a new UNIX domain socket endpoint.
|
|
12
28
|
# @parameter path [String] The path to the UNIX socket.
|
|
13
29
|
# @parameter type [Integer] The socket type (defaults to Socket::SOCK_STREAM).
|
|
14
30
|
# @parameter options [Hash] Additional options to pass to the parent class.
|
|
15
31
|
def initialize(path, type = Socket::SOCK_STREAM, **options)
|
|
16
|
-
# I wonder if we should implement chdir behaviour in here if path is longer than 104 characters.
|
|
17
|
-
super(Address.unix(path, type), **options)
|
|
18
|
-
|
|
19
32
|
@path = path
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
address = Address.unix(path, type)
|
|
36
|
+
rescue ArgumentError
|
|
37
|
+
path = self.class.short_path_for(path)
|
|
38
|
+
address = Address.unix(path, type)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
super(address, **options)
|
|
20
42
|
end
|
|
21
43
|
|
|
22
44
|
# Get a string representation of the UNIX endpoint.
|
|
@@ -28,11 +50,28 @@ module IO::Endpoint
|
|
|
28
50
|
# Get a detailed string representation of the UNIX endpoint.
|
|
29
51
|
# @returns [String] A detailed string representation including the path.
|
|
30
52
|
def inspect
|
|
31
|
-
|
|
53
|
+
target_path = @address.unix_path
|
|
54
|
+
|
|
55
|
+
if @path == target_path
|
|
56
|
+
"\#<#{self.class} path=#{@path.inspect}>"
|
|
57
|
+
else
|
|
58
|
+
"\#<#{self.class} path=#{@path.inspect} target=#{target_path.inspect}>"
|
|
59
|
+
end
|
|
32
60
|
end
|
|
33
61
|
|
|
34
62
|
# @attribute [String] The path to the UNIX socket.
|
|
35
|
-
|
|
63
|
+
def path
|
|
64
|
+
@path
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Check if a symlink is used for this endpoint.
|
|
68
|
+
#
|
|
69
|
+
# A symlink is created when the original path exceeds the system's maximum UNIX socket path length and a shorter temporary path is used for the actual socket.
|
|
70
|
+
#
|
|
71
|
+
# @returns [Boolean] True if the original path differs from the socket path, indicating a symlink is required.
|
|
72
|
+
def symlink?
|
|
73
|
+
File.symlink?(@path)
|
|
74
|
+
end
|
|
36
75
|
|
|
37
76
|
# Check if the socket is currently bound and accepting connections.
|
|
38
77
|
# @returns [Boolean] True if the socket is bound and accepting connections, false otherwise.
|
|
@@ -52,16 +91,61 @@ module IO::Endpoint
|
|
|
52
91
|
# @returns [Array(Socket)] The bound socket.
|
|
53
92
|
# @raises [Errno::EADDRINUSE] If the socket is still in use by another process.
|
|
54
93
|
def bind(...)
|
|
55
|
-
super
|
|
94
|
+
result = super
|
|
95
|
+
create_symlink_if_required!
|
|
96
|
+
return result
|
|
56
97
|
rescue Errno::EADDRINUSE
|
|
57
98
|
# 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.
|
|
58
99
|
if !bound?
|
|
59
|
-
|
|
100
|
+
unlink_stale_paths!
|
|
60
101
|
retry
|
|
61
102
|
else
|
|
62
103
|
raise
|
|
63
104
|
end
|
|
64
105
|
end
|
|
106
|
+
|
|
107
|
+
# Read a symlink, returning nil if the file does not exist.
|
|
108
|
+
#
|
|
109
|
+
# @parameter path [String] The path to the symlink.
|
|
110
|
+
# @returns [String | Nil] The target of the symlink, or nil if the file does not exist.
|
|
111
|
+
private def read_link(path)
|
|
112
|
+
File.readlink(path)
|
|
113
|
+
rescue # Errno::ENOENT, Errno::EINVAL
|
|
114
|
+
# The file is not a symlink, or the symlink is invalid.
|
|
115
|
+
nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Create a symlink to the actual socket path if required.
|
|
119
|
+
private def create_symlink_if_required!
|
|
120
|
+
# Ensure the directory exists:
|
|
121
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
|
122
|
+
|
|
123
|
+
# This is the actual path we want to use for the socket:
|
|
124
|
+
target_path = @address.unix_path
|
|
125
|
+
|
|
126
|
+
# If it's the same as the original path, we are done:
|
|
127
|
+
return if @path == target_path
|
|
128
|
+
|
|
129
|
+
# Otherwise, we need might need to create a symlink:
|
|
130
|
+
if read_link(target_path) == @path
|
|
131
|
+
return
|
|
132
|
+
else
|
|
133
|
+
File.unlink(@path) rescue nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Create symlink at @path (original long path) pointing to target_path (short socket path)
|
|
137
|
+
File.symlink(target_path, @path)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private def unlink_stale_paths!
|
|
141
|
+
File.unlink(@path) rescue nil
|
|
142
|
+
|
|
143
|
+
target_path = @address.unix_path
|
|
144
|
+
|
|
145
|
+
if @path != target_path
|
|
146
|
+
File.unlink(target_path) rescue nil
|
|
147
|
+
end
|
|
148
|
+
end
|
|
65
149
|
end
|
|
66
150
|
|
|
67
151
|
# @parameter path [String]
|
data/lib/io/endpoint/version.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2023-
|
|
4
|
+
# Copyright, 2023-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
# @namespace
|
|
7
7
|
class IO
|
|
8
8
|
# @namespace
|
|
9
9
|
module Endpoint
|
|
10
|
-
VERSION = "0.17.
|
|
10
|
+
VERSION = "0.17.2"
|
|
11
11
|
end
|
|
12
12
|
end
|
data/lib/io/endpoint.rb
CHANGED
data/license.md
CHANGED
data/readme.md
CHANGED
|
@@ -16,6 +16,10 @@ Please see the [project documentation](https://socketry.github.io/io-endpoint) f
|
|
|
16
16
|
|
|
17
17
|
Please see the [project releases](https://socketry.github.io/io-endpointreleases/index) for all releases.
|
|
18
18
|
|
|
19
|
+
### v0.17.2
|
|
20
|
+
|
|
21
|
+
- When the unix path is bigger than what can fit into `struct sockaddr_un`, a shorter temporary path will be used instead and a symlink created at the original path.
|
|
22
|
+
|
|
19
23
|
### v0.17.1
|
|
20
24
|
|
|
21
25
|
- Add `#to_s` and `#inspect` for `IO::Endpoint::NamedEndpoints`.
|
|
@@ -54,10 +58,6 @@ Please see the [project releases](https://socketry.github.io/io-endpointreleases
|
|
|
54
58
|
|
|
55
59
|
- Propagate options assigned to composite endpoint to nested endpoints.
|
|
56
60
|
|
|
57
|
-
### v0.12.0
|
|
58
|
-
|
|
59
|
-
- Expose `size` and internal endpoints for composite endpoint.
|
|
60
|
-
|
|
61
61
|
## See Also
|
|
62
62
|
|
|
63
63
|
- [async-io](https://github.com/socketry/async-io) — Where this implementation originally came from.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.17.2
|
|
4
|
+
|
|
5
|
+
- When the unix path is bigger than what can fit into `struct sockaddr_un`, a shorter temporary path will be used instead and a symlink created at the original path.
|
|
6
|
+
|
|
3
7
|
## v0.17.1
|
|
4
8
|
|
|
5
9
|
- Add `#to_s` and `#inspect` for `IO::Endpoint::NamedEndpoints`.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
|
Binary file
|