io-stream 0.10.0 → 0.11.1
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/stream/buffered.rb +14 -7
- data/lib/io/stream/connection_reset_error.rb +7 -0
- data/lib/io/stream/generic.rb +9 -1
- data/lib/io/stream/openssl.rb +1 -1
- data/lib/io/stream/readable.rb +33 -8
- data/lib/io/stream/shim/buffered.rb +1 -1
- data/lib/io/stream/shim/readable.rb +1 -1
- data/lib/io/stream/string_buffer.rb +1 -1
- data/lib/io/stream/version.rb +2 -2
- data/lib/io/stream/writable.rb +15 -1
- data/lib/io/stream.rb +1 -1
- data/readme.md +5 -5
- data/releases.md +5 -0
- data.tar.gz.sig +0 -0
- metadata +3 -2
- 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: aa0f71cc4addc72776d1dbc02c14d0edb79fc0ae250aebb7f0d4924f6b251701
|
|
4
|
+
data.tar.gz: b5f6ec1328debef8a9b9f9d8593f8a929504e5f0cc170cb780fec41a75ac38f2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd297845e8fdcabd8879baa92e46908129d585a378bf982a1e6f051d67748d216aa7435cbd391bebf2ae364838893c372666a1c10d5de36fcef4e91884377cd1
|
|
7
|
+
data.tar.gz: 857c75d7a920b8f4b6dbcda4746ae41e059eb936cda6f1ea347191843996e00af4a87d4f6e04b0be219c1b4199f59d9ccb3b1114a15619f131186aba68b833e5
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/lib/io/stream/buffered.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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
6
|
require_relative "generic"
|
|
7
|
+
require_relative "connection_reset_error"
|
|
7
8
|
|
|
8
9
|
module IO::Stream
|
|
9
10
|
# A buffered stream implementation that wraps an underlying IO object to provide efficient buffered reading and writing.
|
|
@@ -59,34 +60,34 @@ module IO::Stream
|
|
|
59
60
|
@timeout = nil
|
|
60
61
|
end
|
|
61
62
|
end
|
|
62
|
-
|
|
63
|
+
|
|
63
64
|
# @attribute [IO] The wrapped IO object.
|
|
64
65
|
attr :io
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
# Get the underlying IO object.
|
|
67
68
|
# @returns [IO] The underlying IO object.
|
|
68
69
|
def to_io
|
|
69
70
|
@io.to_io
|
|
70
71
|
end
|
|
71
|
-
|
|
72
|
+
|
|
72
73
|
# Check if the stream is closed.
|
|
73
74
|
# @returns [Boolean] True if the stream is closed.
|
|
74
75
|
def closed?
|
|
75
76
|
@io.closed?
|
|
76
77
|
end
|
|
77
|
-
|
|
78
|
+
|
|
78
79
|
# Close the read end of the stream.
|
|
79
80
|
def close_read
|
|
80
81
|
@io.close_read
|
|
81
82
|
end
|
|
82
|
-
|
|
83
|
+
|
|
83
84
|
# Close the write end of the stream.
|
|
84
85
|
def close_write
|
|
85
86
|
super
|
|
86
87
|
ensure
|
|
87
88
|
@io.close_write
|
|
88
89
|
end
|
|
89
|
-
|
|
90
|
+
|
|
90
91
|
# Check if the stream is readable.
|
|
91
92
|
# @returns [Boolean] True if the stream is readable.
|
|
92
93
|
def readable?
|
|
@@ -146,6 +147,12 @@ module IO::Stream
|
|
|
146
147
|
return result
|
|
147
148
|
end
|
|
148
149
|
end
|
|
150
|
+
rescue OpenSSL::SSL::SSLError => error
|
|
151
|
+
if error.message =~ /unexpected eof while reading/
|
|
152
|
+
raise ConnectionResetError, "Connection reset by peer!"
|
|
153
|
+
end
|
|
154
|
+
rescue Errno::ECONNRESET
|
|
155
|
+
raise ConnectionResetError, "Connection reset by peer!"
|
|
149
156
|
rescue Errno::EBADF
|
|
150
157
|
raise ::IOError, "stream closed"
|
|
151
158
|
end
|
data/lib/io/stream/generic.rb
CHANGED
|
@@ -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-2025, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "string_buffer"
|
|
7
7
|
require_relative "readable"
|
|
@@ -18,6 +18,14 @@ module IO::Stream
|
|
|
18
18
|
include Readable
|
|
19
19
|
include Writable
|
|
20
20
|
|
|
21
|
+
# Check if a method is async-safe.
|
|
22
|
+
#
|
|
23
|
+
# @parameter method [Symbol] The method name to check.
|
|
24
|
+
# @returns [Symbol | Boolean] The concurrency guard for the given method.
|
|
25
|
+
def self.async_safe?(method)
|
|
26
|
+
Readable.async_safe?(method) || Writable.async_safe?(method)
|
|
27
|
+
end
|
|
28
|
+
|
|
21
29
|
# Initialize a new generic stream.
|
|
22
30
|
# @parameter options [Hash] Options passed to included modules.
|
|
23
31
|
def initialize(**options)
|
data/lib/io/stream/openssl.rb
CHANGED
data/lib/io/stream/readable.rb
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright,
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "string_buffer"
|
|
7
7
|
|
|
8
8
|
module IO::Stream
|
|
9
9
|
# The default block size for IO buffers. Defaults to 256KB (optimized for modern SSDs and networks).
|
|
10
10
|
BLOCK_SIZE = ENV.fetch("IO_STREAM_BLOCK_SIZE", 1024*256).to_i
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
# The minimum read size for efficient I/O operations. Defaults to the same as BLOCK_SIZE.
|
|
13
13
|
MINIMUM_READ_SIZE = ENV.fetch("IO_STREAM_MINIMUM_READ_SIZE", BLOCK_SIZE).to_i
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
# The maximum read size for a single read operation. This limit exists because:
|
|
16
16
|
# 1. System calls like read() cannot handle requests larger than SSIZE_MAX
|
|
17
17
|
# 2. Very large reads can cause memory pressure and poor interactive performance
|
|
@@ -25,6 +25,31 @@ module IO::Stream
|
|
|
25
25
|
#
|
|
26
26
|
# You must implement the `sysread` method to read data from the underlying IO.
|
|
27
27
|
module Readable
|
|
28
|
+
ASYNC_SAFE = {
|
|
29
|
+
read: :readable,
|
|
30
|
+
read_partial: :readable,
|
|
31
|
+
read_exactly: :readable,
|
|
32
|
+
read_until: :readable,
|
|
33
|
+
peek: :readable,
|
|
34
|
+
gets: :readable,
|
|
35
|
+
getc: :readable,
|
|
36
|
+
getbyte: :readable,
|
|
37
|
+
readline: :readable,
|
|
38
|
+
readlines: :readable,
|
|
39
|
+
readable?: :readable,
|
|
40
|
+
fill_read_buffer: :readable,
|
|
41
|
+
eof?: :readable,
|
|
42
|
+
finished?: :readable,
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
# Check if a method is async-safe.
|
|
46
|
+
#
|
|
47
|
+
# @parameter method [Symbol] The method name to check.
|
|
48
|
+
# @returns [Symbol | Boolean] The concurrency guard for the given method.
|
|
49
|
+
def self.async_safe?(method)
|
|
50
|
+
ASYNC_SAFE.fetch(method, false)
|
|
51
|
+
end
|
|
52
|
+
|
|
28
53
|
# Initialize readable stream functionality.
|
|
29
54
|
# @parameter minimum_read_size [Integer] The minimum size for read operations.
|
|
30
55
|
# @parameter maximum_read_size [Integer] The maximum size for read operations.
|
|
@@ -41,21 +66,21 @@ module IO::Stream
|
|
|
41
66
|
|
|
42
67
|
super(**, &block) if defined?(super)
|
|
43
68
|
end
|
|
44
|
-
|
|
69
|
+
|
|
45
70
|
attr_accessor :minimum_read_size
|
|
46
|
-
|
|
71
|
+
|
|
47
72
|
# Legacy accessor for backwards compatibility
|
|
48
73
|
# @returns [Integer] The minimum read size.
|
|
49
74
|
def block_size
|
|
50
75
|
@minimum_read_size
|
|
51
76
|
end
|
|
52
|
-
|
|
77
|
+
|
|
53
78
|
# Legacy setter for backwards compatibility
|
|
54
79
|
# @parameter value [Integer] The minimum read size.
|
|
55
80
|
def block_size=(value)
|
|
56
81
|
@minimum_read_size = value
|
|
57
82
|
end
|
|
58
|
-
|
|
83
|
+
|
|
59
84
|
# Read data from the stream.
|
|
60
85
|
# @parameter size [Integer | Nil] The number of bytes to read. If nil, read until end of stream.
|
|
61
86
|
# @parameter buffer [String | Nil] An optional buffer to fill with data instead of allocating a new string.
|
|
@@ -113,7 +138,7 @@ module IO::Stream
|
|
|
113
138
|
return String.new(encoding: Encoding::BINARY)
|
|
114
139
|
end
|
|
115
140
|
end
|
|
116
|
-
|
|
141
|
+
|
|
117
142
|
if !@finished and @read_buffer.empty?
|
|
118
143
|
fill_read_buffer
|
|
119
144
|
end
|
data/lib/io/stream/version.rb
CHANGED
data/lib/io/stream/writable.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright,
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "readable"
|
|
7
7
|
|
|
@@ -13,6 +13,20 @@ module IO::Stream
|
|
|
13
13
|
#
|
|
14
14
|
# You must implement the `syswrite` method to write data to the underlying IO.
|
|
15
15
|
module Writable
|
|
16
|
+
ASYNC_SAFE = {
|
|
17
|
+
write: true,
|
|
18
|
+
puts: true,
|
|
19
|
+
flush: true,
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# Check if a method is async-safe.
|
|
23
|
+
#
|
|
24
|
+
# @parameter method [Symbol] The method name to check.
|
|
25
|
+
# @returns [Symbol | Boolean] The concurrency guard for the given method.
|
|
26
|
+
def self.async_safe?(method)
|
|
27
|
+
ASYNC_SAFE.fetch(method, false)
|
|
28
|
+
end
|
|
29
|
+
|
|
16
30
|
# Initialize writable stream functionality.
|
|
17
31
|
# @parameter minimum_write_size [Integer] The minimum buffer size before flushing.
|
|
18
32
|
def initialize(minimum_write_size: MINIMUM_WRITE_SIZE, **, &block)
|
data/lib/io/stream.rb
CHANGED
data/readme.md
CHANGED
|
@@ -12,6 +12,11 @@ Please see the [project documentation](https://socketry.github.io/io-stream) for
|
|
|
12
12
|
|
|
13
13
|
Please see the [project releases](https://socketry.github.io/io-streamreleases/index) for all releases.
|
|
14
14
|
|
|
15
|
+
### v0.11.0
|
|
16
|
+
|
|
17
|
+
- Introduce `class IO::Stream::ConnectionResetError < Errno::ECONNRESET` to standardize connection reset error handling across different IO types.
|
|
18
|
+
- `OpenSSL::SSL::SSLSocket` raises `OpenSSL::SSL::SSLError` on connection reset, while other IO types raise `Errno::ECONNRESET`. `SSLError` is now rescued and re-raised as `IO::Stream::ConnectionResetError` for consistency.
|
|
19
|
+
|
|
15
20
|
### v0.10.0
|
|
16
21
|
|
|
17
22
|
- Rename `done?` to `finished?` for clarity and consistency.
|
|
@@ -54,11 +59,6 @@ Please see the [project releases](https://socketry.github.io/io-streamreleases/i
|
|
|
54
59
|
- Ensure TLS connections have correct buffering behavior.
|
|
55
60
|
- Improve test suite organization and readability.
|
|
56
61
|
|
|
57
|
-
### v0.4.2
|
|
58
|
-
|
|
59
|
-
- Add external test suite for better integration testing.
|
|
60
|
-
- Update dependencies and improve code style with RuboCop.
|
|
61
|
-
|
|
62
62
|
## See Also
|
|
63
63
|
|
|
64
64
|
- [async-io](https://github.com/socketry/async-io) — Where this implementation originally came from.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.11.0
|
|
4
|
+
|
|
5
|
+
- Introduce `class IO::Stream::ConnectionResetError < Errno::ECONNRESET` to standardize connection reset error handling across different IO types.
|
|
6
|
+
- `OpenSSL::SSL::SSLSocket` raises `OpenSSL::SSL::SSLError` on connection reset, while other IO types raise `Errno::ECONNRESET`. `SSLError` is now rescued and re-raised as `IO::Stream::ConnectionResetError` for consistency.
|
|
7
|
+
|
|
3
8
|
## v0.10.0
|
|
4
9
|
|
|
5
10
|
- Rename `done?` to `finished?` for clarity and consistency.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: io-stream
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -44,6 +44,7 @@ extra_rdoc_files: []
|
|
|
44
44
|
files:
|
|
45
45
|
- lib/io/stream.rb
|
|
46
46
|
- lib/io/stream/buffered.rb
|
|
47
|
+
- lib/io/stream/connection_reset_error.rb
|
|
47
48
|
- lib/io/stream/generic.rb
|
|
48
49
|
- lib/io/stream/openssl.rb
|
|
49
50
|
- lib/io/stream/readable.rb
|
|
@@ -75,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
75
76
|
- !ruby/object:Gem::Version
|
|
76
77
|
version: '0'
|
|
77
78
|
requirements: []
|
|
78
|
-
rubygems_version: 3.6.
|
|
79
|
+
rubygems_version: 3.6.9
|
|
79
80
|
specification_version: 4
|
|
80
81
|
summary: Provides a generic stream wrapper for IO instances.
|
|
81
82
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|