tcp-client 0.9.1 → 0.9.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: fe13751730310529097b79992b58a5ed212ecc4119c576c04bcf7b0c4a0373c7
4
- data.tar.gz: 558f73ee8e06309c8d6ca52cdc4309ceac853a9587b6891959b67f5d49c89413
3
+ metadata.gz: d29104bd490679a8fcb517f949e021cd1d2da263f3a60d622790bc2349faffab
4
+ data.tar.gz: c7ebaf4f9f83eaf68b51bc47bb91fc5be5d446ef3e80b009bc93bca9d3508ef5
5
5
  SHA512:
6
- metadata.gz: a2a9d54d6de01896b83180e7e94afde9a1e2b8f62ca24c9e91d63a7c809a06286357fdecb5a3ad6fce1dceaaa50067a6f64263c83f4069d07b3ad837db138b9d
7
- data.tar.gz: ac6168903ebb5c953e850fb97d80281c63b70b208335d34611f57829199e623fac3fbea85959d09d8c9ddec1edbe23ffef23cd9e5e94e788b74b0ded665dd5c2
6
+ metadata.gz: 5e8c282afbefecb35973f7c563cb07782f8dd0e5df760c89d79aa42424784818c5c0e056c40139554642da8b24823aa9fbb7149e0ed7234f40cc51ea5a7a8165
7
+ data.tar.gz: 2281b62117529f4bbeff55e297b67f8142235772b112d30f9530113e23ab4012242d5eb2fed4e8293a40836455259d37c91403f50714f292ee6e531250e4cc76
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --readme README.md
2
+ --title 'tcp-client Documentation'
3
+ --charset utf-8
4
+ --markup markdown
5
+ 'lib/**/*.rb' - 'LICENSE'
data/README.md CHANGED
@@ -2,16 +2,15 @@
2
2
 
3
3
  A TCP client implementation with working timeout support.
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/tcp-client.svg)](https://badge.fury.io/rb/tcp-client)
5
+ - Gem: [rubygems.org](https://rubygems.org/gems/tcp-client)
6
+ - Source: [github.com](https://github.com/mblumtritt/tcp-client)
7
+ - Help: [rubydoc.info](https://rubydoc.info/github/mblumtritt/tcp-client/main/index)
8
+
6
9
 
7
10
  ## Description
8
11
 
9
12
  This Gem implements a TCP client with (optional) SSL support. It is an easy to use, versatile configurable client that can correctly handle time limits. Unlike other implementations, this client respects predefined/configurable time limits for each method (`connect`, `read`, `write`). Deadlines for a sequence of read/write actions can also be monitored.
10
13
 
11
- ## Help
12
-
13
- The latest help can be found at [rubydoc.info](https://rubydoc.info/github/mblumtritt/tcp-client/main/index)
14
-
15
14
  ## Sample
16
15
 
17
16
  ```ruby
data/gems.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source('https://rubygems.org') { gemspec }
3
+ source 'https://rubygems.org'
4
+ gemspec
@@ -21,24 +21,31 @@ class TCPClient
21
21
  # Initializes an address
22
22
  # @overload initialize(addr)
23
23
  # The addr can be specified as
24
- # - a valid named address containing the port like "my.host.test:80"
25
- # - a valid TCPv4 address like "142.250.181.206:80"
26
- # - a valid TCPv6 address like "[2001:16b8:5093:3500:ad77:abe6:eb88:47b6]:80"
27
24
  #
28
- # @param addr [String] address string
25
+ # - a valid named address containing the port like "my.host.test:80"
26
+ # - a valid TCPv4 address like "142.250.181.206:80"
27
+ # - a valid TCPv6 address like
28
+ # "[2001:16b8:5093:3500:ad77:abe6:eb88:47b6]:80"
29
29
  #
30
- # @overload initialize(address)
31
- # Used to create a copy
30
+ # @example create an Address instance with a host name and port
31
+ # Address.new('www.google.com:80')
32
+ #
33
+ # @param addr [String] address containing host and port name
32
34
  #
33
- # @param address [Address]
34
35
  #
35
36
  # @overload initialize(addrinfo)
36
37
  #
38
+ # @example create an Address with an Addrinfo
39
+ # Address.new(Addrinfo.tcp('www.google.com', 'http'))
40
+ #
37
41
  # @param addrinfo [Addrinfo] containing the addressed host and port
38
42
  #
39
43
  # @overload initialize(port)
40
44
  # Adresses the port on the local machine.
41
45
  #
46
+ # @example create an Address for localhost on port 80
47
+ # Address.new(80)
48
+ #
42
49
  # @param port [Integer] the addressed port
43
50
  #
44
51
  def initialize(addr)
@@ -22,7 +22,7 @@ class TCPClient
22
22
  # @return [Configuration] the initialized configuration
23
23
  #
24
24
  # @overload create(&block)
25
- # Shorthand to initialize a new configuration.
25
+ # Shorthand to create a new configuration within a code block.
26
26
  #
27
27
  # @example
28
28
  # config = TCPClient::Configuration.create do |cfg|
@@ -30,14 +30,14 @@ class TCPClient
30
30
  # cfg.ssl_params = { min_version: :TLS1_2, max_version: :TLS1_3 }
31
31
  # end
32
32
  #
33
- # @yieldparam cfg {Configuration}
33
+ # @yieldparam configuration {Configuration}
34
34
  #
35
35
  # @return [Configuration] the initialized configuration
36
36
  #
37
37
  def self.create(options = {})
38
- cfg = new(options)
39
- yield(cfg) if block_given?
40
- cfg
38
+ configuration = new(options)
39
+ yield(configuration) if block_given?
40
+ configuration
41
41
  end
42
42
 
43
43
  #
@@ -47,14 +47,18 @@ class TCPClient
47
47
  # @option options [Boolean] :buffered, see {#buffered}
48
48
  # @option options [Boolean] :keep_alive, see {#keep_alive}
49
49
  # @option options [Boolean] :reverse_lookup, see {#reverse_lookup}
50
- # @option options [Boolean] :normalize_network_errors, see {#normalize_network_errors}
50
+ # @option options [Hash<Symbol, Object>] :ssl_params, see {#ssl_params}
51
51
  # @option options [Numeric] :connect_timeout, see {#connect_timeout}
52
- # @option options [Exception] :connect_timeout_error, see {#connect_timeout_error}
52
+ # @option options [Exception] :connect_timeout_error, see
53
+ # {#connect_timeout_error}
53
54
  # @option options [Numeric] :read_timeout, see {#read_timeout}
54
55
  # @option options [Exception] :read_timeout_error, see {#read_timeout_error}
55
56
  # @option options [Numeric] :write_timeout, see {#write_timeout}
56
- # @option options [Exception] :write_timeout_error, see {#write_timeout_error}
57
- # @option options [Hash<Symbol, Object>] :ssl_params, see {#ssl_params}
57
+ # @option options [Exception] :write_timeout_error, see
58
+ # {#write_timeout_error}
59
+ # @option options [Boolean] :normalize_network_errors, see
60
+ # {#normalize_network_errors}
61
+ #
58
62
  #
59
63
  def initialize(options = {})
60
64
  @buffered = @keep_alive = @reverse_lookup = true
@@ -66,10 +70,13 @@ class TCPClient
66
70
  options.each_pair { |attribute, value| set(attribute, value) }
67
71
  end
68
72
 
73
+ # @!group Instance Attributes Socket Level
74
+
69
75
  #
70
- # Enables/disables use of Socket-level buffers.
76
+ # Enables/disables use of Socket-level buffering
71
77
  #
72
- # @return [true] if the connection is allowed to use internal buffers (default)
78
+ # @return [true] if the connection is allowed to use internal buffers
79
+ # (default)
73
80
  # @return [false] if buffering is not allowed
74
81
  #
75
82
  attr_reader :buffered
@@ -81,7 +88,8 @@ class TCPClient
81
88
  #
82
89
  # Enables/disables use of Socket-level keep alive handling.
83
90
  #
84
- # @return [true] if the connection is allowed to use keep alive signals (default)
91
+ # @return [true] if the connection is allowed to use keep alive signals
92
+ # (default)
85
93
  # @return [false] if the connection should not check keep alive
86
94
  #
87
95
  attr_reader :keep_alive
@@ -93,7 +101,8 @@ class TCPClient
93
101
  #
94
102
  # Enables/disables address lookup.
95
103
  #
96
- # @return [true] if the connection is allowed to lookup the address (default)
104
+ # @return [true] if the connection is allowed to lookup the address
105
+ # (default)
97
106
  # @return [false] if the address lookup is not required
98
107
  #
99
108
  attr_reader :reverse_lookup
@@ -103,55 +112,44 @@ class TCPClient
103
112
  end
104
113
 
105
114
  #
106
- # Enables/disables if network exceptions should be raised as {NetworkError}.
107
- #
108
- # @return [true] if all network exceptions should be raised as {NetworkError}
109
- # @return [false] if socket/system errors should not be normalzed (default)
115
+ # @!parse attr_reader :ssl?
116
+ # @return [Boolean] wheter SSL is configured, see {#ssl_params}
110
117
  #
111
- attr_reader :normalize_network_errors
112
-
113
- def normalize_network_errors=(value)
114
- @normalize_network_errors = value ? true : false
118
+ def ssl?
119
+ @ssl_params ? true : false
115
120
  end
116
121
 
117
122
  #
118
- # @attribute [w] timeout
119
- # Shorthand to set timeout value for connect, read and write at once or to disable any timeout monitoring
123
+ # Parameters used to initialize a SSL context.
120
124
  #
121
- # @return [Numeric] maximum time in seconds for any action
122
- # @return [nil] if all timeout monitoring should be disabled (default)
123
- #
124
- # @see #connect_timeout
125
- # @see #read_timeout
126
- # @see #write_timeout
125
+ # @return [Hash<Symbol, Object>] SSL parameters for the SSL context
126
+ # @return [nil] if no SSL should be used (default)
127
127
  #
128
- def timeout=(value)
129
- @connect_timeout = @write_timeout = @read_timeout = seconds(value)
130
- end
128
+ attr_reader :ssl_params
131
129
 
132
- #
133
- # @attribute [w] timeout_error
134
- # Shorthand to configure exception class raised when connect, read or write exceeded the configured timeout
135
- #
136
- # @return [Class] exception class raised
137
- #
138
- # @raise [NotAnExceptionError] if given argument is not an Exception class
139
- #
140
- # @see #connect_timeout_error
141
- # @see #read_timeout_error
142
- # @see #write_timeout_error
143
- #
144
- def timeout_error=(value)
145
- raise(NotAnExceptionError, value) unless exception_class?(value)
146
- @connect_timeout_error =
147
- @read_timeout_error = @write_timeout_error = value
130
+ def ssl_params=(value)
131
+ @ssl_params =
132
+ if value.respond_to?(:to_hash)
133
+ Hash[value.to_hash]
134
+ elsif value.respond_to?(:to_h)
135
+ Hash[value.to_h]
136
+ else
137
+ value ? {} : nil
138
+ end
148
139
  end
140
+ alias ssl= ssl_params=
141
+
142
+ # @!endgroup
149
143
 
144
+ # @!group Instance Attributes Timeout Monitoring
145
+
146
+ #
147
+ # The maximum time in seconds to establish a connection.
150
148
  #
151
- # Configures maximum time in seconds to establish a connection.
149
+ # @return [Numeric] maximum time in seconds
150
+ # @return [nil] if the connect time should not be monitored (default)
152
151
  #
153
- # @return [Numeric] maximum time in seconds to establish a connection
154
- # @return [nil] if the connect time should not be checked (default)
152
+ # @see TCPClient#connect
155
153
  #
156
154
  attr_reader :connect_timeout
157
155
 
@@ -160,7 +158,10 @@ class TCPClient
160
158
  end
161
159
 
162
160
  #
163
- # @return [Class] exception class raised if a {TCPClient#connect} timed out
161
+ # The exception class which will be raised if {TCPClient#connect} can not
162
+ # be finished in time.
163
+ #
164
+ # @return [Class] exception class raised
164
165
  # @raise [NotAnExceptionError] if given argument is not an Exception class
165
166
  #
166
167
  attr_reader :connect_timeout_error
@@ -171,10 +172,12 @@ class TCPClient
171
172
  end
172
173
 
173
174
  #
174
- # Configures maximum time in seconds to finish a {TCPClient#read}.
175
+ # The maximum time in seconds to read from a connection.
176
+ #
177
+ # @return [Numeric] maximum time in seconds
178
+ # @return [nil] if the read time should not be monitored (default)
175
179
  #
176
- # @return [Numeric] maximum time in seconds to finish a {TCPClient#read} request
177
- # @return [nil] if the read time should not be checked (default)
180
+ # @see TCPClient#read
178
181
  #
179
182
  attr_reader :read_timeout
180
183
 
@@ -183,7 +186,10 @@ class TCPClient
183
186
  end
184
187
 
185
188
  #
186
- # @return [Class] exception class raised if a {TCPClient#read} timed out
189
+ # The exception class which will be raised if {TCPClient#read} can not be
190
+ # finished in time.
191
+ #
192
+ # @return [Class] exception class raised
187
193
  # @raise [NotAnExceptionError] if given argument is not an Exception class
188
194
  #
189
195
  attr_reader :read_timeout_error
@@ -194,10 +200,12 @@ class TCPClient
194
200
  end
195
201
 
196
202
  #
197
- # Configures maximum time in seconds to finish a {TCPClient#write}.
203
+ # The maximum time in seconds to write to a connection.
198
204
  #
199
- # @return [Numeric] maximum time in seconds to finish a {TCPClient#write} request
200
- # @return [nil] if the write time should not be checked (default)
205
+ # @return [Numeric] maximum time in seconds
206
+ # @return [nil] if the write time should not be monitored (default)
207
+ #
208
+ # @see TCPClient#write
201
209
  #
202
210
  attr_reader :write_timeout
203
211
 
@@ -206,7 +214,10 @@ class TCPClient
206
214
  end
207
215
 
208
216
  #
209
- # @return [Class] exception class raised if a {TCPClient#write} timed out
217
+ # The exception class which will be raised if {TCPClient#write} can not be
218
+ # finished in time.
219
+ #
220
+ # @return [Class] exception class raised
210
221
  # @raise [NotAnExceptionError] if given argument is not an Exception class
211
222
  #
212
223
  attr_reader :write_timeout_error
@@ -217,48 +228,78 @@ class TCPClient
217
228
  end
218
229
 
219
230
  #
220
- # @attribute ssl?
221
- # @return [Boolean] wheter SSL is configured, see {#ssl_params}
231
+ # @attribute [w] timeout
232
+ # Shorthand to set maximum time in seconds for all timeut monitoring.
222
233
  #
223
- def ssl?
224
- @ssl_params ? true : false
234
+ # @return [Numeric] maximum time in seconds for any actwion
235
+ # @return [nil] if all timeout monitoring should be disabled (default)
236
+ #
237
+ # @see #connect_timeout
238
+ # @see #read_timeout
239
+ # @see #write_timeout
240
+ #
241
+ def timeout=(value)
242
+ @connect_timeout = @write_timeout = @read_timeout = seconds(value)
225
243
  end
226
244
 
227
245
  #
228
- # Configures the SSL parameters used to initialize a SSL context.
246
+ # @attribute [w] timeout_error
247
+ # Shorthand to set the exception class wich will by raised by any timeut.
229
248
  #
230
- # @return [Hash<Symbol, Object>] SSL parameters for the SSL context
231
- # @return [nil] if no SSL should be used (default)
249
+ # @return [Class] exception class raised
232
250
  #
233
- attr_reader :ssl_params
251
+ # @raise [NotAnExceptionError] if given argument is not an Exception class
252
+ #
253
+ # @see #connect_timeout_error
254
+ # @see #read_timeout_error
255
+ # @see #write_timeout_error
256
+ #
257
+ def timeout_error=(value)
258
+ raise(NotAnExceptionError, value) unless exception_class?(value)
259
+ @connect_timeout_error =
260
+ @read_timeout_error = @write_timeout_error = value
261
+ end
234
262
 
235
- def ssl_params=(value)
236
- @ssl_params =
237
- if value.respond_to?(:to_hash)
238
- Hash[value.to_hash]
239
- elsif value.respond_to?(:to_h)
240
- Hash[value.to_h]
241
- else
242
- value ? {} : nil
243
- end
263
+ # @!endgroup
264
+
265
+ #
266
+ # Enables/disables if network exceptions should be raised as {NetworkError}.
267
+ #
268
+ # This allows to handle all network/socket related exceptions like
269
+ # `SocketError`, `OpenSSL::SSL::SSLError`, `IOError`, etc. in a uniform
270
+ # manner. If this option is set to true all these error cases are raised as
271
+ # {NetworkError} and can be easily captured.
272
+ #
273
+ # @return [true] if all network exceptions should be raised as
274
+ # {NetworkError}
275
+ # @return [false] if socket/system errors should not be normalzed (default)
276
+ #
277
+ attr_reader :normalize_network_errors
278
+
279
+ def normalize_network_errors=(value)
280
+ @normalize_network_errors = value ? true : false
244
281
  end
245
- alias ssl= ssl_params=
246
282
 
247
283
  #
248
- # @return [Hash] configuration as a Hash
284
+ # Convert `self` to a Hash containing all attributes.
285
+ #
286
+ # @return [Hash<Symbol, Object>]
287
+ #
288
+ # @see #initialize
249
289
  #
250
290
  def to_h
251
291
  {
252
292
  buffered: @buffered,
253
293
  keep_alive: @keep_alive,
254
294
  reverse_lookup: @reverse_lookup,
295
+ ssl_params: @ssl_params,
255
296
  connect_timeout: @connect_timeout,
256
297
  connect_timeout_error: @connect_timeout_error,
257
298
  read_timeout: @read_timeout,
258
299
  read_timeout_error: @read_timeout_error,
259
300
  write_timeout: @write_timeout,
260
301
  write_timeout_error: @write_timeout_error,
261
- ssl_params: @ssl_params
302
+ normalize_network_errors: @normalize_network_errors
262
303
  }
263
304
  end
264
305
 
@@ -7,13 +7,17 @@ class TCPClient
7
7
 
8
8
  class << self
9
9
  #
10
- # @return [Configuration] used by default if no dedicated configuration was specified
10
+ # The default configuration.
11
+ # This is used by default if no dedicated configuration was specified to
12
+ # {.open} or {#connect}.
13
+ #
14
+ # @return [Configuration]
11
15
  #
12
16
  attr_reader :default_configuration
13
17
 
14
18
  #
15
- # Configure the default configuration which is used if no dedicated
16
- # configuration was specified.
19
+ # Configure the {.default_configuration} which is used if no dedicated
20
+ # configuration was specified to {.open} or {#connect}.
17
21
  #
18
22
  # @example
19
23
  # TCPClient.configure do |cfg|
@@ -33,11 +37,19 @@ class TCPClient
33
37
  end
34
38
 
35
39
  class Configuration
36
- #
37
- # @return [Configuration] used by default if no dedicated configuration was specified
38
- #
39
- def self.default
40
- TCPClient.default_configuration
40
+ class << self
41
+ #
42
+ # @!parse attr_reader :default
43
+ # @return [Configuration] used by default if no dedicated configuration
44
+ # was specified
45
+ #
46
+ # @see TCPClient.open
47
+ # @see TCPClient.with_deadline
48
+ # @see TCPClient#connect
49
+ #
50
+ def default
51
+ TCPClient.default_configuration
52
+ end
41
53
  end
42
54
  end
43
55
  end
@@ -20,9 +20,12 @@ class TCPClient
20
20
  end
21
21
 
22
22
  #
23
- # Raised when a an invalid timeout value was specified.
23
+ # Raised when an invalid timeout value was specified.
24
24
  #
25
25
  class InvalidDeadLineError < ArgumentError
26
+ #
27
+ # @param timeout [Object] the invalid value
28
+ #
26
29
  def initialize(timeout)
27
30
  super("invalid deadline - #{timeout}")
28
31
  end
@@ -32,6 +35,9 @@ class TCPClient
32
35
  # Raised by {Configuration} when an undefined attribute should be set.
33
36
  #
34
37
  class UnknownAttributeError < ArgumentError
38
+ #
39
+ # @param attribute [Object] the undefined atttribute
40
+ #
35
41
  def initialize(attribute)
36
42
  super("unknown attribute - #{attribute}")
37
43
  end
@@ -41,6 +47,9 @@ class TCPClient
41
47
  # Raised when a given timeout exception parameter is not an exception class.
42
48
  #
43
49
  class NotAnExceptionError < TypeError
50
+ #
51
+ # @param object [Object] the invalid object
52
+ #
44
53
  def initialize(object)
45
54
  super("exception class required - #{object.inspect}")
46
55
  end
@@ -74,17 +83,19 @@ class TCPClient
74
83
  #
75
84
  # Initializes the instance with an optional message.
76
85
  #
77
- # the message will be generated from {#action} when not specified.
86
+ # The message will be generated from {#action} when not specified.
87
+ #
78
88
  # @overload initialize
79
89
  # @overload initialize(message)
80
90
  #
81
- # @param message [String, #to_s] the error message
91
+ # @param message [#to_s] the error message
82
92
  #
83
93
  def initialize(message = nil)
84
94
  super(message || "unable to #{action} in time")
85
95
  end
86
96
 
87
97
  #
98
+ # @attribute [r] action
88
99
  # @return [Symbol] the action which timed out
89
100
  #
90
101
  def action
@@ -97,7 +108,8 @@ class TCPClient
97
108
  #
98
109
  class ConnectTimeoutError < TimeoutError
99
110
  #
100
- # @return [Symbol] the action which timed out: +:connect+
111
+ # @attribute [r] action
112
+ # @return [Symbol] the action which timed out: `:connect`
101
113
  #
102
114
  def action
103
115
  :connect
@@ -105,11 +117,12 @@ class TCPClient
105
117
  end
106
118
 
107
119
  #
108
- # Raised by default whenever a {TCPClient.read} timed out.
120
+ # Raised by default whenever a {TCPClient#read} timed out.
109
121
  #
110
122
  class ReadTimeoutError < TimeoutError
111
123
  #
112
- # @return [Symbol] the action which timed out: +:read+
124
+ # @attribute [r] action
125
+ # @return [Symbol] the action which timed out: :read`
113
126
  #
114
127
  def action
115
128
  :read
@@ -117,11 +130,12 @@ class TCPClient
117
130
  end
118
131
 
119
132
  #
120
- # Raised by default whenever a {TCPClient.write} timed out.
133
+ # Raised by default whenever a {TCPClient#write} timed out.
121
134
  #
122
135
  class WriteTimeoutError < TimeoutError
123
136
  #
124
- # @return [Symbol] the action which timed out: +:write+
137
+ # @attribute [r] action
138
+ # @return [Symbol] the action which timed out: `:write`
125
139
  #
126
140
  def action
127
141
  :write
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TCPClient
4
- #
5
- # The current gem version.
6
- #
7
- VERSION = '0.9.1'
4
+ VERSION = '0.9.2'
8
5
  end
data/lib/tcp-client.rb CHANGED
@@ -15,7 +15,7 @@ require_relative 'tcp-client/version'
15
15
  # All connect/read/write actions can be monitored to ensure that all actions
16
16
  # terminate before given time limits - or raise an exception.
17
17
  #
18
- # @example - request to Google.com and limit all network interactions to 1.5 seconds
18
+ # @example request to Google.com and limit network interactions to 1.5 seconds
19
19
  # TCPClient.with_deadline(1.5, 'www.google.com:443') do |client|
20
20
  # client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")
21
21
  # client.read(12)
@@ -26,7 +26,9 @@ require_relative 'tcp-client/version'
26
26
  class TCPClient
27
27
  #
28
28
  # Creates a new instance which is connected to the server on the given
29
- # address and uses the given or the {.default_configuration}.
29
+ # `address`.
30
+ #
31
+ # If no `configuration` is given, the {.default_configuration} will be used.
30
32
  #
31
33
  # If an optional block is given, then the block's result is returned and the
32
34
  # connection will be closed when the block execution ends.
@@ -36,8 +38,10 @@ class TCPClient
36
38
  # If no block is giiven the connected client instance is returned.
37
39
  # This can be used as a shorthand to create & connect a client.
38
40
  #
39
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
40
- # @param configuration [Configuration] the {Configuration} to be used for this instance
41
+ # @param address [Address, String, Addrinfo, Integer] the address to connect
42
+ # to, see {Address#initialize} for valid formats
43
+ # @param configuration [Configuration] the {Configuration} to be used for
44
+ # this instance
41
45
  #
42
46
  # @yieldparam client [TCPClient] the connected client
43
47
  # @yieldreturn [Object] any result
@@ -56,23 +60,29 @@ class TCPClient
56
60
 
57
61
  #
58
62
  # Yields a new instance which is connected to the server on the given
59
- # address and uses the given or the {.default_configuration}.
60
- # It ensures to close the connection when the block execution ends.
61
- # It also limits all {#read} and {#write} actions within the block to a given
62
- # time.
63
+ # `address`.It limits all {#read} and {#write} actions within the block to
64
+ # the given time.
65
+ #
66
+ # It ensures to close the connection when the block execution ends and returns
67
+ # the block`s result.
63
68
  #
64
69
  # This can be used to create an ad-hoc connection which is garanteed to be
65
- # closed and which read/write calls should not last longer than the timeout
66
- # limit.
70
+ # closed and which {#read}/{#write} call sequence should not last longer than
71
+ # the `timeout`.
72
+ #
73
+ # If no `configuration` is given, the {.default_configuration} will be used.
67
74
  #
68
- # @param timeout [Numeric] maximum time in seconds for all {#read} and {#write} calls within the block
69
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
70
- # @param configuration [Configuration] the {Configuration} to be used for this instance
75
+ # @param timeout [Numeric] maximum time in seconds for all {#read} and
76
+ # {#write} calls within the block
77
+ # @param address [Address, String, Addrinfo, Integer] the address to connect
78
+ # to, see {Address#initialize} for valid formats
79
+ # @param configuration [Configuration] the {Configuration} to be used for
80
+ # this instance
71
81
  #
72
82
  # @yieldparam client [TCPClient] the connected client
73
83
  # @yieldreturn [Object] any result
74
84
  #
75
- # @return [Object] the block result
85
+ # @return [Object] the block's result
76
86
  #
77
87
  # @see #with_deadline
78
88
  #
@@ -89,17 +99,17 @@ class TCPClient
89
99
  end
90
100
 
91
101
  #
92
- # @return [Address] the address used for this client
102
+ # @return [Address] the address used by this client instance
93
103
  #
94
104
  attr_reader :address
95
105
 
96
106
  #
97
- # @return [Configuration] the configuration used by this client.
107
+ # @return [Configuration] the configuration used by this client instance
98
108
  #
99
109
  attr_reader :configuration
100
110
 
101
111
  #
102
- # @attribute [r] closed?
112
+ # @!parse attr_reader :closed?
103
113
  # @return [Boolean] true when the connection is closed, false when connected
104
114
  #
105
115
  def closed?
@@ -107,30 +117,44 @@ class TCPClient
107
117
  end
108
118
 
109
119
  #
110
- # @return [String] the currently used address as text.
120
+ # Close the current connection if connected.
111
121
  #
112
- # @see Address#to_s
122
+ # @return [self]
113
123
  #
114
- def to_s
115
- @address&.to_s || ''
124
+ def close
125
+ @socket&.close
126
+ self
127
+ rescue *NETWORK_ERRORS
128
+ self
129
+ ensure
130
+ @socket = @deadline = nil
116
131
  end
117
132
 
118
133
  #
119
- # Establishes a new connection to a given address.
134
+ # Establishes a new connection to a given `address`.
120
135
  #
121
- # It accepts a connection-specific configuration or uses the global {.default_configuration}. The {#configuration} used by this instance will
136
+ # It accepts a connection-specific configuration or uses the
137
+ # {.default_configuration}. The {#configuration} used by this instance will
122
138
  # be a copy of the configuration used for this method call. This allows to
123
139
  # configure the behavior per connection.
124
140
  #
125
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
126
- # @param configuration [Configuration] the {Configuration} to be used for this instance
127
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +connect_timeout+.
128
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +connect_timeout_error+.
141
+ # The optional `timeout` and `exception` parameters allow to override the
142
+ # `connect_timeout` and `connect_timeout_error` values.
143
+ #
144
+ # @param address [Address, String, Addrinfo, Integer] the address to connect
145
+ # to, see {Address#initialize} for valid formats
146
+ # @param configuration [Configuration] the {Configuration} to be used for
147
+ # this instance
148
+ # @param timeout [Numeric] maximum time in seconds to connect
149
+ # @param exception [Class] exception class to be used when the connect timeout
150
+ # reached
129
151
  #
130
152
  # @return [self]
131
153
  #
132
154
  # @raise {NoOpenSSLError} if SSL should be used but OpenSSL is not avail
133
155
  #
156
+ # @see NetworkError
157
+ #
134
158
  def connect(address, configuration = nil, timeout: nil, exception: nil)
135
159
  close if @socket
136
160
  @address = Address.new(address)
@@ -141,37 +165,72 @@ class TCPClient
141
165
  end
142
166
 
143
167
  #
144
- # Close the current connection.
168
+ # Flush all internal buffers (write all through).
145
169
  #
146
170
  # @return [self]
147
171
  #
148
- def close
149
- @socket&.close
150
- self
151
- rescue *NETWORK_ERRORS
172
+ def flush
173
+ stem_errors { @socket&.flush }
152
174
  self
153
- ensure
154
- @socket = @deadline = nil
155
175
  end
156
176
 
157
177
  #
158
- # Executes a block with a given overall timeout.
178
+ # Read the given `nbytes` or the next available buffer from server.
179
+ #
180
+ # The optional `timeout` and `exception` parameters allow to override the
181
+ # `read_timeout` and `read_timeout_error` values of the used {#configuration}.
182
+ #
183
+ # @param nbytes [Integer] the number of bytes to read
184
+ # @param timeout [Numeric] maximum time in seconds to read
185
+ # @param exception [Class] exception class to be used when the read timeout
186
+ # reached
187
+ #
188
+ # @return [String] the read buffer
189
+ #
190
+ # @raise [NotConnectedError] if {#connect} was not called before
159
191
  #
160
- # When you like to ensure that a complete read/write communication sequence
161
- # with the server is finished before a given amount of time you can use this
162
- # method to define such a deadline.
192
+ # @see NetworkError
163
193
  #
164
- # @example - ensure to send a welcome message and receive a 64 byte answer from server
194
+ def read(nbytes = nil, timeout: nil, exception: nil)
195
+ raise(NotConnectedError) if closed?
196
+ deadline = create_deadline(timeout, configuration.read_timeout)
197
+ return stem_errors { @socket.read(nbytes) } unless deadline.valid?
198
+ exception ||= configuration.read_timeout_error
199
+ stem_errors(exception) do
200
+ @socket.read_with_deadline(nbytes, deadline, exception)
201
+ end
202
+ end
203
+
204
+ #
205
+ # @return [String] the currently used address as text.
206
+ #
207
+ # @see Address#to_s
208
+ #
209
+ def to_s
210
+ @address&.to_s || ''
211
+ end
212
+
213
+ #
214
+ # Execute a block with a given overall time limit.
215
+ #
216
+ # When you like to ensure that a complete {#read}/{#write} communication
217
+ # sequence with the server is finished before a given amount of time you use
218
+ # this method.
219
+ #
220
+ # @example ensure to send SMTP welcome message and receive a 4 byte answer
165
221
  # answer = client.with_deadline(2.5) do
166
- # client.write('Helo')
167
- # client.read(64)
222
+ # client.write('HELO')
223
+ # client.read(4)
168
224
  # end
225
+ # # answer is EHLO when server speaks fluent SMPT
169
226
  #
170
- # @param timeout [Numeric] maximum time in seconds for all {#read} and {#write} calls within the block
227
+ # @param timeout [Numeric] maximum time in seconds for all {#read} and
228
+ # {#write} calls within the block
171
229
  #
172
230
  # @yieldparam client [TCPClient] self
231
+ # @yieldreturn [Object] any result
173
232
  #
174
- # @return [Object] result of the given block
233
+ # @return [Object] the block`s result
175
234
  #
176
235
  # @raise [NoBlockGivenError] if the block is missing
177
236
  #
@@ -186,32 +245,16 @@ class TCPClient
186
245
  end
187
246
 
188
247
  #
189
- # Read the given nbytes or the next available buffer from server.
190
- #
191
- # @param nbytes [Integer] the number of bytes to read
192
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +read_timeout+.
193
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +read_timeout_error+.
194
- #
195
- # @return [String] buffer read
196
- #
197
- # @raise [NotConnectedError] if {#connect} was not called before
198
- #
199
- def read(nbytes = nil, timeout: nil, exception: nil)
200
- raise(NotConnectedError) if closed?
201
- deadline = create_deadline(timeout, configuration.read_timeout)
202
- return stem_errors { @socket.read(nbytes) } unless deadline.valid?
203
- exception ||= configuration.read_timeout_error
204
- stem_errors(exception) do
205
- @socket.read_with_deadline(nbytes, deadline, exception)
206
- end
207
- end
208
-
248
+ # Write the given `messages` to the server.
209
249
  #
210
- # Write the given messages to the server.
250
+ # The optional `timeout` and `exception` parameters allow to override the
251
+ # `write_timeout` and `write_timeout_error` values of the used
252
+ # {#configuration}.
211
253
  #
212
- # @param messages [Array<String>] messages to write
213
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +write_timeout+.
214
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +write_timeout_error+.
254
+ # @param messages [String] one or more messages to write
255
+ # @param timeout [Numeric] maximum time in seconds to write
256
+ # @param exception [Class] exception class to be used when the write timeout
257
+ # reached
215
258
  #
216
259
  # @return [Integer] bytes written
217
260
  #
@@ -229,16 +272,6 @@ class TCPClient
229
272
  end
230
273
  end
231
274
 
232
- #
233
- # Flush all internal buffers (write all through).
234
- #
235
- # @return [self]
236
- #
237
- def flush
238
- stem_errors { @socket&.flush }
239
- self
240
- end
241
-
242
275
  private
243
276
 
244
277
  def create_deadline(timeout, default)
data/rakefile.rb CHANGED
@@ -6,8 +6,7 @@ require 'rspec/core/rake_task'
6
6
  require 'yard'
7
7
 
8
8
  $stdout.sync = $stderr.sync = true
9
-
10
- CLOBBER << 'prj' << 'doc'
9
+ CLOBBER << 'prj' << 'doc' << '.yardoc'
11
10
  task(:default) { exec('rake --tasks') }
12
11
  RSpec::Core::RakeTask.new { |task| task.ruby_opts = %w[-w] }
13
12
  YARD::Rake::YardocTask.new { |task| task.stats_options = %w[--list-undoc] }
@@ -182,6 +182,7 @@ RSpec.describe TCPClient::Configuration do
182
182
  read_timeout_error: TCPClient::ReadTimeoutError,
183
183
  write_timeout: 3,
184
184
  write_timeout_error: TCPClient::WriteTimeoutError,
185
+ normalize_network_errors: false,
185
186
  ssl_params: {
186
187
  min_version: :TLS1_2,
187
188
  max_version: :TLS1_3
data/tcp-client.gemspec CHANGED
@@ -5,12 +5,11 @@ require_relative './lib/tcp-client/version'
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'tcp-client'
7
7
  spec.version = TCPClient::VERSION
8
- spec.author = 'Mike Blumtritt'
9
-
10
8
  spec.required_ruby_version = '>= 2.7.0'
11
9
 
10
+ spec.author = 'Mike Blumtritt'
12
11
  spec.summary = 'A TCP client implementation with working timeout support.'
13
- spec.description = <<~DESCRIPTION
12
+ spec.description = <<~description
14
13
  This Gem implements a TCP client with (optional) SSL support.
15
14
  It is an easy to use, versatile configurable client that can correctly
16
15
  handle time limits.
@@ -18,15 +17,15 @@ Gem::Specification.new do |spec|
18
17
  predefined/configurable time limits for each method
19
18
  (`connect`, `read`, `write`). Deadlines for a sequence of read/write
20
19
  actions can also be monitored.
21
- DESCRIPTION
20
+ description
21
+
22
22
  spec.homepage = 'https://github.com/mblumtritt/tcp-client'
23
23
  spec.license = 'BSD-3-Clause'
24
-
25
- spec.metadata['source_code_uri'] = 'https://github.com/mblumtritt/tcp-client'
26
- spec.metadata['documentation_uri'] =
27
- 'https://rubydoc.info/github/mblumtritt/tcp-client'
28
- spec.metadata['bug_tracker_uri'] =
29
- 'https://github.com/mblumtritt/tcp-client/issues'
24
+ spec.metadata.merge!(
25
+ 'source_code_uri' => 'https://github.com/mblumtritt/tcp-client',
26
+ 'bug_tracker_uri' => 'https://github.com/mblumtritt/tcp-client/issues',
27
+ 'documentation_uri' => 'https://rubydoc.info/github/mblumtritt/tcp-client'
28
+ )
30
29
 
31
30
  spec.add_development_dependency 'bundler'
32
31
  spec.add_development_dependency 'rake'
@@ -36,6 +35,5 @@ Gem::Specification.new do |spec|
36
35
  all_files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
37
36
  spec.test_files = all_files.grep(%r{^spec/})
38
37
  spec.files = all_files - spec.test_files
39
-
40
38
  spec.extra_rdoc_files = %w[README.md LICENSE]
41
39
  end
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.9.1
4
+ version: 0.9.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-12-01 00:00:00.000000000 Z
11
+ date: 2021-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -82,6 +82,7 @@ extra_rdoc_files:
82
82
  - LICENSE
83
83
  files:
84
84
  - ".gitignore"
85
+ - ".yardopts"
85
86
  - LICENSE
86
87
  - README.md
87
88
  - gems.rb
@@ -111,8 +112,8 @@ licenses:
111
112
  - BSD-3-Clause
112
113
  metadata:
113
114
  source_code_uri: https://github.com/mblumtritt/tcp-client
114
- documentation_uri: https://rubydoc.info/github/mblumtritt/tcp-client
115
115
  bug_tracker_uri: https://github.com/mblumtritt/tcp-client/issues
116
+ documentation_uri: https://rubydoc.info/github/mblumtritt/tcp-client
116
117
  post_install_message:
117
118
  rdoc_options: []
118
119
  require_paths: