tcp-client 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4738c2c07c1163d9a991fa08978d148ebdee182193a90103ecba277cd783f4b3
4
- data.tar.gz: a69ecf05054b5260ab9a324226d5d0a592e337a09a68865c4702e37f4a948a4a
3
+ metadata.gz: 404b30eadc3a1f6f255257328ad49b1cd0827bd502f86e08d283bb94a1ab6447
4
+ data.tar.gz: e4825578860b8b74ae180988beecf1faef75230e456e20da9a5ce86baa4c729e
5
5
  SHA512:
6
- metadata.gz: 8c348cb8696ab9fec32321499b4fa62f169ce5b62e4d703df009a7762cd40e9c6e9cbe22c52affce4a493f4d473907f6b051a74e2a46e9de9ff5fc13d24bdd24
7
- data.tar.gz: 40d45b9e44f4f7d6fd8e9514ae0e507c39e7177df8cca986b13f461753d00de579bae04578db49a0b5a67b86e6d9527e35cc8db87eb5ff4646b972c9ac4a6b90
6
+ metadata.gz: 662962d4c32d91547f15623c92a8ae7951cb96189619bea97ea55d02725a2d05c7ea665f92d27e9dbbbb3e541d1e5bb04b40437a54e986d1240fa19b77bd91ae
7
+ data.tar.gz: dbc18f0ee4b6d025f5fe1a2a9be257ad280687dc3b165d4e2bfbc3d68976548172df2da865a58ad0801ac6c0b50244d33438f08570c33f852143bb6c16309ab1
data/lib/tcp-client.rb CHANGED
@@ -20,22 +20,22 @@ class TCPClient
20
20
  attr_reader :address
21
21
 
22
22
  def initialize
23
- @socket = @address = @write_timeout = @read_timeout = @deadline = nil
23
+ @socket = @address = @deadline = @cfg = nil
24
24
  end
25
25
 
26
26
  def to_s
27
27
  @address ? @address.to_s : ''
28
28
  end
29
29
 
30
- def connect(addr, configuration, exception: ConnectTimeoutError)
30
+ def connect(addr, configuration, exception: nil)
31
31
  close
32
32
  NoOpenSSL.raise! if configuration.ssl? && !defined?(SSLSocket)
33
33
  @address = Address.new(addr)
34
- @socket = TCPSocket.new(@address, configuration, exception)
35
- configuration.ssl? &&
34
+ @cfg = configuration.dup
35
+ exception ||= configuration.connect_timeout_error
36
+ @socket = TCPSocket.new(@address, @cfg, exception)
37
+ @cfg.ssl? &&
36
38
  @socket = SSLSocket.new(@socket, @address, configuration, exception)
37
- @write_timeout = configuration.write_timeout
38
- @read_timeout = configuration.read_timeout
39
39
  self
40
40
  end
41
41
 
@@ -53,8 +53,8 @@ class TCPClient
53
53
  end
54
54
 
55
55
  def with_deadline(timeout)
56
- NoBlockGiven.raise! unless block_given?
57
56
  previous_deadline = @deadline
57
+ NoBlockGiven.raise! unless block_given?
58
58
  tm = timeout&.to_f
59
59
  InvalidDeadLine.raise! unless tm&.positive?
60
60
  @deadline = Time.now + tm
@@ -63,34 +63,45 @@ class TCPClient
63
63
  @deadline = previous_deadline
64
64
  end
65
65
 
66
- def read(nbytes, timeout: nil, exception: ReadTimeoutError)
66
+ def read(nbytes, timeout: nil, exception: nil)
67
67
  NotConnected.raise! if closed?
68
- if timeout.nil? && @deadline
69
- return @socket.read_with_deadline(nbytes, @deadline, exception)
70
- end
71
- timeout = (timeout || @read_timeout).to_f
72
- if timeout.positive?
73
- @socket.read_with_deadline(nbytes, Time.now + timeout, exception)
74
- else
75
- @socket.read(nbytes)
76
- end
68
+ timeout.nil? && @deadline and
69
+ return read_with_deadline(nbytes, @deadline, exception)
70
+ timeout = (timeout || @cfg.read_timeout).to_f
71
+ return @socket.read(nbytes) unless timeout.positive?
72
+ read_with_deadline(nbytes, Time.now + timeout, exception)
77
73
  end
78
74
 
79
- def write(*msg, timeout: nil, exception: WriteTimeoutError)
75
+ def write(*msg, timeout: nil, exception: nil)
80
76
  NotConnected.raise! if closed?
81
- if timeout.nil? && @deadline
82
- return @socket.write_with_deadline(msg.join.b, @deadline, exception)
83
- end
84
- timeout = (timeout || @read_timeout).to_f
85
- if timeout.positive?
86
- @socket.write_with_deadline(msg.join.b, Time.now + timeout, exception)
87
- else
88
- @socket.write(*msg)
89
- end
77
+ timeout.nil? && @deadline and
78
+ return write_with_deadline(msg, @deadline, exception)
79
+ timeout = (timeout || @cfg.write_timeout).to_f
80
+ return @socket.write(*msg) unless timeout.positive?
81
+ write_with_deadline(msg, Time.now + timeout, exception)
90
82
  end
91
83
 
92
84
  def flush
93
85
  @socket.flush unless closed?
94
86
  self
95
87
  end
88
+
89
+ private
90
+
91
+ def read_with_deadline(nbytes, deadline, exception)
92
+ @socket.read_with_deadline(
93
+ nbytes,
94
+ deadline,
95
+ exception || @cfg.read_timeout_error
96
+ )
97
+ end
98
+
99
+ def write_with_deadline(msg, deadline, exception)
100
+ exception ||= @cfg.write_timeout_error
101
+ result = 0
102
+ msg.each do |chunk|
103
+ result += @socket.write_with_deadline(chunk.b, deadline, exception)
104
+ end
105
+ result
106
+ end
96
107
  end
@@ -1,3 +1,5 @@
1
+ require_relative 'errors'
2
+
1
3
  class TCPClient
2
4
  class Configuration
3
5
  def self.create(options = {})
@@ -6,15 +8,38 @@ class TCPClient
6
8
  ret
7
9
  end
8
10
 
9
- attr_reader :buffered, :keep_alive, :reverse_lookup, :timeout
11
+ attr_reader :buffered,
12
+ :keep_alive,
13
+ :reverse_lookup,
14
+ :timeout,
15
+ :connect_timeout,
16
+ :read_timeout,
17
+ :write_timeout,
18
+ :connect_timeout_error,
19
+ :read_timeout_error,
20
+ :write_timeout_error
10
21
  attr_accessor :ssl_params
11
22
 
12
23
  def initialize(options = {})
13
24
  @buffered = @keep_alive = @reverse_lookup = true
14
25
  self.timeout = @ssl_params = nil
26
+ @connect_timeout_error = ConnectTimeoutError
27
+ @read_timeout_error = ReadTimeoutError
28
+ @write_timeout_error = WriteTimeoutError
15
29
  options.each_pair { |attribute, value| set(attribute, value) }
16
30
  end
17
31
 
32
+ def freeze
33
+ @ssl_params.freeze
34
+ super
35
+ end
36
+
37
+ def initialize_copy(_org)
38
+ super
39
+ @ssl_params = @ssl_params.dup
40
+ self
41
+ end
42
+
18
43
  def ssl?
19
44
  @ssl_params ? true : false
20
45
  end
@@ -38,32 +63,41 @@ class TCPClient
38
63
  end
39
64
 
40
65
  def timeout=(seconds)
41
- @timeout = seconds(seconds)
42
- @connect_timeout = @write_timeout = @read_timeout = nil
43
- end
44
-
45
- def connect_timeout
46
- @connect_timeout || @timeout
66
+ @timeout =
67
+ @connect_timeout = @write_timeout = @read_timeout = seconds(seconds)
47
68
  end
48
69
 
49
70
  def connect_timeout=(seconds)
50
71
  @connect_timeout = seconds(seconds)
51
72
  end
52
73
 
53
- def write_timeout
54
- @write_timeout || @timeout
74
+ def read_timeout=(seconds)
75
+ @read_timeout = seconds(seconds)
55
76
  end
56
77
 
57
78
  def write_timeout=(seconds)
58
79
  @write_timeout = seconds(seconds)
59
80
  end
60
81
 
61
- def read_timeout
62
- @read_timeout || @timeout
82
+ def timeout_error=(exception)
83
+ NotAnException.raise!(exception) unless exception_class?(exception)
84
+ @connect_timeout_error =
85
+ @read_timeout_error = @write_timeout_error = exception
63
86
  end
64
87
 
65
- def read_timeout=(seconds)
66
- @read_timeout = seconds(seconds)
88
+ def connect_timeout_error=(exception)
89
+ NotAnException.raise!(exception) unless exception_class?(exception)
90
+ @connect_timeout_error = exception
91
+ end
92
+
93
+ def read_timeout_error=(exception)
94
+ NotAnException.raise!(exception) unless exception_class?(exception)
95
+ @read_timeout_error = exception
96
+ end
97
+
98
+ def write_timeout_error=(exception)
99
+ NotAnException.raise!(exception) unless exception_class?(exception)
100
+ @write_timeout_error = exception
67
101
  end
68
102
 
69
103
  def to_h
@@ -75,6 +109,9 @@ class TCPClient
75
109
  connect_timeout: @connect_timeout,
76
110
  read_timeout: @read_timeout,
77
111
  write_timeout: @write_timeout,
112
+ connect_timeout_error: @connect_timeout_error,
113
+ read_timeout_error: @read_timeout_error,
114
+ write_timeout_error: @write_timeout_error,
78
115
  ssl_params: @ssl_params
79
116
  }
80
117
  end
@@ -90,10 +127,14 @@ class TCPClient
90
127
 
91
128
  private
92
129
 
130
+ def exception_class?(value)
131
+ value.is_a?(Class) && value < Exception
132
+ end
133
+
93
134
  def set(attribute, value)
94
135
  public_send("#{attribute}=", value)
95
136
  rescue NoMethodError
96
- raise(ArgumentError, "unknown attribute - #{attribute}")
137
+ UnknownAttribute.raise!(attribute)
97
138
  end
98
139
 
99
140
  def seconds(value)
@@ -21,6 +21,18 @@ class TCPClient
21
21
  end
22
22
  end
23
23
 
24
+ class UnknownAttribute < ArgumentError
25
+ def self.raise!(attribute)
26
+ raise(self, "unknown attribute - #{attribute}", caller(1))
27
+ end
28
+ end
29
+
30
+ class NotAnException < TypeError
31
+ def self.raise!(object)
32
+ raise(self, "not a valid exception class - #{object.inspect}", caller(1))
33
+ end
34
+ end
35
+
24
36
  class NotConnected < SocketError
25
37
  def self.raise!
26
38
  raise(self, 'client not connected', caller(1))
@@ -1,3 +1,3 @@
1
1
  class TCPClient
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.2.2'.freeze
3
3
  end
@@ -39,7 +39,8 @@ class ConfigurationTest < MiniTest::Test
39
39
  connect_timeout: 1,
40
40
  read_timeout: 2,
41
41
  write_timeout: 3,
42
- ssl: true
42
+ ssl: true,
43
+ connect_timeout_error: IOError
43
44
  )
44
45
  refute(subject.buffered)
45
46
  refute(subject.keep_alive)
@@ -48,6 +49,8 @@ class ConfigurationTest < MiniTest::Test
48
49
  assert_same(2, subject.read_timeout)
49
50
  assert_same(3, subject.write_timeout)
50
51
  assert(subject.ssl?)
52
+ assert_same(IOError, subject.connect_timeout_error)
53
+ assert_same(TCPClient::ReadTimeoutError, subject.read_timeout_error)
51
54
  end
52
55
 
53
56
  def test_invalid_option
@@ -88,6 +91,18 @@ class ConfigurationTest < MiniTest::Test
88
91
  assert_same(42, subject.write_timeout)
89
92
  end
90
93
 
94
+ def test_timeout_error_overwrite
95
+ subject = TCPClient::Configuration.new
96
+ assert_same(TCPClient::ConnectTimeoutError, subject.connect_timeout_error)
97
+ assert_same(TCPClient::ReadTimeoutError, subject.read_timeout_error)
98
+ assert_same(TCPClient::WriteTimeoutError, subject.write_timeout_error)
99
+
100
+ subject.timeout_error = IOError
101
+ assert_same(IOError, subject.connect_timeout_error)
102
+ assert_same(IOError, subject.read_timeout_error)
103
+ assert_same(IOError, subject.write_timeout_error)
104
+ end
105
+
91
106
  def test_compare
92
107
  a = TCPClient::Configuration.new
93
108
  b = TCPClient::Configuration.new
@@ -95,4 +110,32 @@ class ConfigurationTest < MiniTest::Test
95
110
  assert(a == b)
96
111
  assert(a === b)
97
112
  end
113
+
114
+ def test_dup
115
+ source =
116
+ TCPClient::Configuration.new(
117
+ buffered: false,
118
+ keep_alive: false,
119
+ reverse_lookup: false,
120
+ connect_timeout: 1,
121
+ read_timeout: 2,
122
+ write_timeout: 3,
123
+ ssl: {
124
+ ssl_version: :TLSv1_2
125
+ }
126
+ )
127
+ shadow = source.dup.freeze
128
+
129
+ # some changes
130
+ source.buffered = true
131
+ source.write_timeout = 5
132
+ source.ssl_params[:err] = true
133
+ source.timeout_error = IOError
134
+
135
+ refute_equal(source.__id__, shadow.__id__)
136
+ refute(shadow.buffered)
137
+ assert_equal(3, shadow.write_timeout)
138
+ assert_equal({ ssl_version: :TLSv1_2 }, shadow.ssl_params)
139
+ assert_same(TCPClient::ReadTimeoutError, shadow.read_timeout_error)
140
+ end
98
141
  end
@@ -67,7 +67,7 @@ class TCPClientTest < MiniTest::Test
67
67
  start_time = Time.now
68
68
  subject.read(42, timeout: timeout)
69
69
  end
70
- assert_in_delta(timeout, Time.now - start_time, 0.11)
70
+ assert_in_delta(timeout, Time.now - start_time, 0.15)
71
71
  end
72
72
  end
73
73
 
@@ -85,7 +85,7 @@ class TCPClientTest < MiniTest::Test
85
85
  start_time = Time.now
86
86
  subject.write(*HUGE_AMOUNT_OF_DATA, timeout: timeout)
87
87
  end
88
- assert_in_delta(timeout, Time.now - start_time, 0.11)
88
+ assert_in_delta(timeout, Time.now - start_time, 0.15)
89
89
  end
90
90
  end
91
91
 
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: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-22 00:00:00.000000000 Z
11
+ date: 2021-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler