tcp-client 0.9.1 → 0.9.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: 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: