tcp-client 0.2.0 → 0.2.2

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: 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