sanford-protocol 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -110,6 +110,18 @@ connection.write(outgoing_data)
110
110
 
111
111
  For incoming messages, it reads them off the socket, validate them, and return the decoded body data. For outgoing messages, it encodes the message body from given data, adds the appropiate message headers, and writes the message to the socket.
112
112
 
113
+ #### Timeout
114
+
115
+ When reading data from a connection, you can optionally pass a timeout value. If given, the connection will block and wait until data is ready to be read. If a timeout occurs, the connection will raise `TimeoutError`.
116
+
117
+ ```ruby
118
+ begin
119
+ connection.read(10) # timeout after waiting on data for 10s
120
+ rescue Sanford::Protocol::TimeoutError => err
121
+ puts "timeout - so sad :("
122
+ end
123
+ ```
124
+
113
125
  ### Requests And Responses
114
126
 
115
127
  Request and response objects have helpers for sending and receiving data using a connection.
@@ -19,7 +19,8 @@ module Sanford::Protocol
19
19
  # | msg version | msg body size | msg body |
20
20
  # |-----------------|-----------------|----------------------|
21
21
 
22
- def read
22
+ def read(timeout=nil)
23
+ wait_for_data(timeout) if timeout
23
24
  MsgVersion.new{ @socket.read msg_version.bytesize }.validate!
24
25
  size = MsgSize.new{ @socket.decode msg_size, msg_size.bytes }.validate!.value
25
26
  return MsgBody.new{ @socket.decode msg_body, size }.validate!.value
@@ -32,23 +33,38 @@ module Sanford::Protocol
32
33
  @socket.write(msg_version, size, body)
33
34
  end
34
35
 
35
- class Socket < Struct.new(:tcp_socket)
36
- def decode(handler, num_bytes)
37
- handler.decode(read(num_bytes))
38
- end
36
+ private
39
37
 
40
- def encode(handler, data)
41
- handler.encode data
38
+ def wait_for_data(timeout)
39
+ if IO.select([ @socket.tcp_socket ], nil, nil, timeout).nil?
40
+ raise TimeoutError.new(timeout)
42
41
  end
42
+ end
43
43
 
44
- def read(number_of_bytes)
45
- tcp_socket.recvfrom(number_of_bytes).first
46
- end
44
+ end
47
45
 
48
- def write(*binary_strings)
49
- tcp_socket.send(binary_strings.join, 0)
50
- end
46
+ class Socket < Struct.new(:tcp_socket)
47
+ def decode(handler, num_bytes)
48
+ handler.decode(read(num_bytes))
49
+ end
50
+
51
+ def encode(handler, data)
52
+ handler.encode data
51
53
  end
52
54
 
55
+ def read(number_of_bytes)
56
+ tcp_socket.recvfrom(number_of_bytes).first
57
+ end
58
+
59
+ def write(*binary_strings)
60
+ tcp_socket.send(binary_strings.join, 0)
61
+ end
53
62
  end
63
+
64
+ class TimeoutError < RuntimeError
65
+ def initialize(timeout)
66
+ super "Timed out waiting for data to read (#{timeout}s)."
67
+ end
68
+ end
69
+
54
70
  end
@@ -1,5 +1,5 @@
1
1
  module Sanford
2
2
  module Protocol
3
- GEM_VERSION = "0.3.0"
3
+ GEM_VERSION = "0.4.0"
4
4
  end
5
5
  end
@@ -24,4 +24,19 @@ class Sanford::Protocol::Connection
24
24
  end
25
25
  end
26
26
 
27
+ class TimeoutTests < BaseTests
28
+ desc "when timing out on a read"
29
+ setup do
30
+ IO.stubs(:select).returns(nil) # mock IO.select behavior when it times out
31
+ end
32
+ teardown do
33
+ IO.unstub(:select)
34
+ end
35
+
36
+ should "raise `TimeoutError` if given a timeout value" do
37
+ assert_raises(Sanford::Protocol::TimeoutError) { subject.read(1) }
38
+ end
39
+
40
+ end
41
+
27
42
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sanford-protocol
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Collin Redding