tcp-client 1.0.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ed9a12e8872f2399ace7bef72451c8f6b2d7821e4de069e095eb1ca7a5fcb96
4
- data.tar.gz: 4b6b744fb885e99ea320cdfbfe21a9ff1aceaa12beedec2f2b068ceb3e932cd2
3
+ metadata.gz: f087df088e9bdfc71ffd19b01d3f9f7a229f4db510a339a08ea7d02c07a32eda
4
+ data.tar.gz: 4b4d332dcdeb98a2bc81f3e7963973da21336e5b2d89199bfc9b0d2c92c9b122
5
5
  SHA512:
6
- metadata.gz: c4e7417600e74d3709a20b20f5d13804da51d0ff85670ca8a180bd173ae7f07ea513976c2b73c3436a852b5c51a1f6c99a61f917c4be769cd73cb91f9b65684a
7
- data.tar.gz: 197b43ef8e44faec4a6bcd397f71505b3f8f4714a3775248eeaf2984acca4444bd5f8e290cc99be9408870f4a862f1c724cfadd55c114be12a4651027f7d7fd4
6
+ metadata.gz: f0c31448b596bc77288424a2863528714db40576f7201f2927172d0c39cac4086fe976a315347d6da78a96ca022a33e31956533caa02c025b18b7b3e3129d97d
7
+ data.tar.gz: 69dd0aa063a8019c07976b6942f0d08df0f31036eb903040e63cfdc40844c0275396a879a2e7f27332ad9843b2a2ba4326fbccabee3d12e1a3b31a587cb5ba9a
data/.yardopts CHANGED
@@ -2,4 +2,9 @@
2
2
  --title 'tcp-client Documentation'
3
3
  --charset utf-8
4
4
  --markup markdown
5
- 'lib/**/*.rb' - 'README.md' 'LICENSE'
5
+ --tag comment
6
+ --hide-tag comment
7
+ lib/**/*.rb
8
+ -
9
+ README.md
10
+ LICENSE
data/README.md CHANGED
@@ -54,7 +54,7 @@ gem install tcp-client
54
54
  You can use [Bundler](http://gembundler.com/) to add TCPClient to your own project:
55
55
 
56
56
  ```shell
57
- bundle add 'tcp-client'
57
+ bundle add tcp-client
58
58
  ```
59
59
 
60
60
  After that you only need one line of code to have everything together
@@ -336,7 +336,7 @@ class TCPClient
336
336
 
337
337
  private
338
338
 
339
- def as_seconds(value) = value&.to_f&.positive? ? value : nil
339
+ def as_seconds(value) = value.to_f.positive? ? value : nil
340
340
 
341
341
  def as_exception(value)
342
342
  return value if value.is_a?(Class) && value < Exception
@@ -2,15 +2,26 @@
2
2
 
3
3
  class TCPClient
4
4
  class Deadline
5
- def initialize(timeout)
6
- timeout = timeout&.to_f
7
- @deadline = timeout&.positive? ? now + timeout : nil
5
+ attr_accessor :exception
6
+
7
+ def initialize(timeout, exception)
8
+ @timeout = timeout.to_f
9
+ @exception = exception
10
+ @deadline = @timeout.positive? ? now + @timeout : nil
8
11
  end
9
12
 
10
13
  def valid? = !@deadline.nil?
11
14
 
12
15
  def remaining_time
13
- @deadline && (remaining = @deadline - now) > 0 ? remaining : nil
16
+ (remaining = @deadline - now) > 0 ? remaining : timed_out!(caller(1))
17
+ end
18
+
19
+ def timed_out!(call_stack = nil)
20
+ raise(
21
+ @exception,
22
+ "execution expired - #{@timeout} seconds",
23
+ call_stack || caller(1)
24
+ )
14
25
  end
15
26
 
16
27
  private
@@ -13,13 +13,13 @@ class TCPClient
13
13
  class SSLSocket < ::OpenSSL::SSL::SSLSocket
14
14
  include WithDeadline
15
15
 
16
- def initialize(socket, address, configuration, deadline, exception)
16
+ def initialize(socket, address, configuration, deadline)
17
17
  ssl_params = Hash[configuration.ssl_params]
18
18
  super(socket, create_context(ssl_params))
19
19
  self.sync_close = true
20
20
  self.hostname = address.hostname
21
21
  check_new_session if @new_session
22
- deadline.valid? ? connect_with_deadline(deadline, exception) : connect
22
+ deadline.valid? ? connect_with_deadline(deadline) : connect
23
23
  post_connection_check(address.hostname) if should_verify?(ssl_params)
24
24
  end
25
25
 
@@ -41,8 +41,8 @@ class TCPClient
41
41
  end
42
42
  end
43
43
 
44
- def connect_with_deadline(deadline, exception)
45
- with_deadline(deadline, exception) { connect_nonblock(exception: false) }
44
+ def connect_with_deadline(deadline)
45
+ with_deadline(deadline) { connect_nonblock(exception: false) }
46
46
  end
47
47
 
48
48
  def should_verify?(ssl_params)
@@ -8,10 +8,10 @@ class TCPClient
8
8
  class TCPSocket < ::Socket
9
9
  include WithDeadline
10
10
 
11
- def initialize(address, configuration, deadline, exception)
11
+ def initialize(address, configuration, deadline)
12
12
  super(address.addrinfo.ipv6? ? :INET6 : :INET, :STREAM)
13
13
  configure(configuration)
14
- connect_to(as_addr_in(address), deadline, exception)
14
+ connect_to(as_addr_in(address), deadline)
15
15
  end
16
16
 
17
17
  private
@@ -21,11 +21,9 @@ class TCPClient
21
21
  ::Socket.pack_sockaddr_in(addrinfo.ip_port, addrinfo.ip_address)
22
22
  end
23
23
 
24
- def connect_to(addr, deadline, exception)
24
+ def connect_to(addr, deadline)
25
25
  return connect(addr) unless deadline.valid?
26
- with_deadline(deadline, exception) do
27
- connect_nonblock(addr, exception: false)
28
- end
26
+ with_deadline(deadline) { connect_nonblock(addr, exception: false) }
29
27
  end
30
28
 
31
29
  def configure(configuration)
@@ -2,5 +2,5 @@
2
2
 
3
3
  class TCPClient
4
4
  # The current version number.
5
- VERSION = '1.0.0'
5
+ VERSION = '1.0.1'
6
6
  end
@@ -2,22 +2,22 @@
2
2
 
3
3
  class TCPClient
4
4
  module WithDeadline
5
- def read_with_deadline(nbytes, deadline, exception)
6
- raise(exception) unless deadline.remaining_time
7
- return fetch_avail(deadline, exception) if nbytes.nil?
5
+ def read_with_deadline(nbytes, deadline)
6
+ deadline.remaining_time
7
+ return fetch_avail(deadline) if nbytes.nil?
8
8
  @read_buffer ||= ''.b
9
9
  while @read_buffer.bytesize < nbytes
10
- read = fetch_next(deadline, exception)
10
+ read = fetch_next(deadline)
11
11
  read ? @read_buffer << read : (break close)
12
12
  end
13
13
  fetch_slice(nbytes)
14
14
  end
15
15
 
16
- def read_to_with_deadline(sep, deadline, exception)
17
- raise(exception) unless deadline.remaining_time
16
+ def read_to_with_deadline(sep, deadline)
17
+ deadline.remaining_time
18
18
  @read_buffer ||= ''.b
19
19
  while (index = @read_buffer.index(sep)).nil?
20
- read = fetch_next(deadline, exception)
20
+ read = fetch_next(deadline)
21
21
  read ? @read_buffer << read : (break close)
22
22
  end
23
23
  return fetch_slice(index + sep.bytesize) if index
@@ -26,15 +26,13 @@ class TCPClient
26
26
  result
27
27
  end
28
28
 
29
- def write_with_deadline(data, deadline, exception)
29
+ def write_with_deadline(data, deadline)
30
30
  return 0 if (size = data.bytesize).zero?
31
- raise(exception) unless deadline.remaining_time
31
+ deadline.remaining_time
32
32
  result = 0
33
33
  while true
34
34
  written =
35
- with_deadline(deadline, exception) do
36
- write_nonblock(data, exception: false)
37
- end
35
+ with_deadline(deadline) { write_nonblock(data, exception: false) }
38
36
  return result if (result += written) >= size
39
37
  data = data.byteslice(written, data.bytesize - written)
40
38
  end
@@ -42,8 +40,8 @@ class TCPClient
42
40
 
43
41
  private
44
42
 
45
- def fetch_avail(deadline, exception)
46
- if (result = @read_buffer || fetch_next(deadline, exception)).nil?
43
+ def fetch_avail(deadline)
44
+ if (result = @read_buffer || fetch_next(deadline)).nil?
47
45
  close
48
46
  return ''.b
49
47
  end
@@ -59,27 +57,23 @@ class TCPClient
59
57
  result
60
58
  end
61
59
 
62
- def fetch_next(deadline, exception)
63
- with_deadline(deadline, exception) do
64
- read_nonblock(65_536, exception: false)
65
- end
60
+ def fetch_next(deadline)
61
+ with_deadline(deadline) { read_nonblock(65_536, exception: false) }
66
62
  end
67
63
 
68
- def with_deadline(deadline, exception)
64
+ def with_deadline(deadline)
69
65
  while true
70
66
  case ret = yield
71
67
  when :wait_writable
72
- remaining_time = deadline.remaining_time or raise(exception)
73
- wait_write[remaining_time] or raise(exception)
68
+ wait_write[deadline.remaining_time] or deadline.timed_out!
74
69
  when :wait_readable
75
- remaining_time = deadline.remaining_time or raise(exception)
76
- wait_read[remaining_time] or raise(exception)
70
+ wait_read[deadline.remaining_time] or deadline.timed_out!
77
71
  else
78
72
  return ret
79
73
  end
80
74
  end
81
75
  rescue Errno::ETIMEDOUT
82
- raise(exception)
76
+ deadline.timed_out!
83
77
  end
84
78
 
85
79
  def wait_write
data/lib/tcp-client.rb CHANGED
@@ -192,11 +192,15 @@ class TCPClient
192
192
  #
193
193
  def read(nbytes = nil, timeout: nil, exception: nil)
194
194
  raise(NotConnectedError) if closed?
195
- deadline = create_deadline(timeout, configuration.read_timeout)
195
+ deadline =
196
+ create_deadline(
197
+ timeout,
198
+ @configuration.read_timeout,
199
+ exception || @configuration.read_timeout_error
200
+ )
196
201
  return stem_errors { @socket.read(nbytes) } unless deadline.valid?
197
- exception ||= configuration.read_timeout_error
198
- stem_errors(exception) do
199
- @socket.read_with_deadline(nbytes, deadline, exception)
202
+ stem_errors(deadline.exception) do
203
+ @socket.read_with_deadline(nbytes, deadline)
200
204
  end
201
205
  end
202
206
 
@@ -221,13 +225,17 @@ class TCPClient
221
225
  #
222
226
  def readline(separator = $/, chomp: false, timeout: nil, exception: nil)
223
227
  raise(NotConnectedError) if closed?
224
- deadline = create_deadline(timeout, configuration.read_timeout)
228
+ deadline =
229
+ create_deadline(
230
+ timeout,
231
+ @configuration.read_timeout,
232
+ exception || @configuration.read_timeout_error
233
+ )
225
234
  deadline.valid? or
226
235
  return stem_errors { @socket.readline(separator, chomp: chomp) }
227
- exception ||= configuration.read_timeout_error
228
236
  line =
229
- stem_errors(exception) do
230
- @socket.read_to_with_deadline(separator, deadline, exception)
237
+ stem_errors(deadline.exception) do
238
+ @socket.read_to_with_deadline(separator, deadline)
231
239
  end
232
240
  chomp ? line.chomp : line
233
241
  end
@@ -265,7 +273,7 @@ class TCPClient
265
273
  def with_deadline(timeout)
266
274
  previous_deadline = @deadline
267
275
  raise(NoBlockGivenError) unless block_given?
268
- @deadline = Deadline.new(timeout)
276
+ @deadline = Deadline.new(timeout, TimeoutError)
269
277
  raise(InvalidDeadLineError, timeout) unless @deadline.valid?
270
278
  yield(self)
271
279
  ensure
@@ -292,36 +300,46 @@ class TCPClient
292
300
  #
293
301
  def write(*messages, timeout: nil, exception: nil)
294
302
  raise(NotConnectedError) if closed?
295
- deadline = create_deadline(timeout, configuration.write_timeout)
303
+ deadline =
304
+ create_deadline(
305
+ timeout,
306
+ @configuration.write_timeout,
307
+ exception || @configuration.write_timeout_error
308
+ )
296
309
  return stem_errors { @socket.write(*messages) } unless deadline.valid?
297
- exception ||= configuration.write_timeout_error
298
- stem_errors(exception) do
299
- messages.sum do |chunk|
300
- @socket.write_with_deadline(chunk.b, deadline, exception)
301
- end
310
+ stem_errors(deadline.exception) do
311
+ messages.sum { |chunk| @socket.write_with_deadline(chunk.b, deadline) }
302
312
  end
303
313
  end
304
314
 
305
315
  private
306
316
 
307
- def create_deadline(timeout, default)
308
- timeout.nil? && @deadline ? @deadline : Deadline.new(timeout || default)
317
+ def create_deadline(timeout, timeout_default, exception)
318
+ if timeout.nil? && @deadline
319
+ @deadline.exception = exception
320
+ return @deadline
321
+ end
322
+ Deadline.new(timeout || timeout_default, exception)
309
323
  end
310
324
 
311
325
  def create_socket(timeout, exception)
312
- deadline = create_deadline(timeout, configuration.connect_timeout)
313
- exception ||= configuration.connect_timeout_error
314
- stem_errors(exception) do
315
- @socket = TCPSocket.new(address, configuration, deadline, exception)
316
- return @socket unless configuration.ssl?
317
- SSLSocket.new(@socket, address, configuration, deadline, exception)
326
+ deadline =
327
+ create_deadline(
328
+ timeout,
329
+ @configuration.connect_timeout,
330
+ exception || @configuration.connect_timeout_error
331
+ )
332
+ stem_errors(deadline.exception) do
333
+ @socket = TCPSocket.new(address, @configuration, deadline)
334
+ return @socket unless @configuration.ssl?
335
+ SSLSocket.new(@socket, address, @configuration, deadline)
318
336
  end
319
337
  end
320
338
 
321
339
  def stem_errors(except = nil)
322
340
  yield
323
341
  rescue *NETWORK_ERRORS => e
324
- raise unless configuration.normalize_network_errors
342
+ raise unless @configuration.normalize_network_errors
325
343
  except && e.is_a?(except) ? raise : raise(NetworkError, e)
326
344
  end
327
345
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tcp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-03 00:00:00.000000000 Z
11
+ date: 2024-05-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  This gem implements a customizable TCP client class that gives you control
@@ -59,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
59
  - !ruby/object:Gem::Version
60
60
  version: '0'
61
61
  requirements: []
62
- rubygems_version: 3.5.9
62
+ rubygems_version: 3.5.10
63
63
  signing_key:
64
64
  specification_version: 4
65
65
  summary: Use your TCP connections with working timeout.