bertrpc 1.0.0 → 1.1.0

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.
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ = 1.1.0 / 2009-10-27
2
+ * Add read socket timeout
3
+
1
4
  = 1.0.0 / 2009-10-19
2
5
  * No changes. Production ready!
3
6
 
data/README.md CHANGED
@@ -3,7 +3,8 @@ BERTRPC
3
3
 
4
4
  By Tom Preston-Werner (tom@mojombo.com)
5
5
 
6
- BERT-RPC client library for Ruby. Makes it ridiculously simple to interface with BERT-RPC servers.
6
+ BERT-RPC client library for Ruby. Makes it ridiculously simple to interface
7
+ with BERT-RPC servers.
7
8
 
8
9
  See the full BERT-RPC specification at [bert-rpc.org](http://bert-rpc.org).
9
10
 
@@ -12,7 +13,9 @@ This library currently only supports the following BERT-RPC features:
12
13
  * `call` requests
13
14
  * `cast` requests
14
15
 
15
- BERTRPC was developed for GitHub and is currently in production use performing millions of RPC requests every day. The stability and performance have been exemplary.
16
+ BERTRPC was developed for GitHub and is currently in production use performing
17
+ millions of RPC requests every day. The stability and performance have been
18
+ exemplary.
16
19
 
17
20
 
18
21
  Installation
@@ -50,6 +53,18 @@ The underlying BERT-RPC transaction of the above cast is:
50
53
  <- {noreply}
51
54
 
52
55
 
56
+ Documentation
57
+ -------------
58
+
59
+ Creating a service:
60
+
61
+ # No timeout
62
+ svc = BERTRPC::Service.new('localhost', 9999)
63
+
64
+ # 10s socket read timeout, raises BERTRPC::ReadTimeoutError
65
+ svc = BERTRPC::Service.new('localhost', 9999, 10)
66
+
67
+
53
68
  Copyright
54
69
  ---------
55
70
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.1.0
data/bertrpc.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bertrpc}
8
- s.version = "1.0.0"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tom Preston-Werner"]
12
- s.date = %q{2009-10-19}
12
+ s.date = %q{2009-10-27}
13
13
  s.email = %q{tom@mojombo.com}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  "bertrpc.gemspec",
27
27
  "lib/bertrpc.rb",
28
28
  "lib/bertrpc/action.rb",
29
+ "lib/bertrpc/buffered_io.rb",
29
30
  "lib/bertrpc/encodes.rb",
30
31
  "lib/bertrpc/errors.rb",
31
32
  "lib/bertrpc/mod.rb",
@@ -24,7 +24,7 @@ module BERTRPC
24
24
  end
25
25
 
26
26
  def transaction(bert_request)
27
- sock = TCPSocket.new(@svc.host, @svc.port)
27
+ sock = connect_to(@svc.host, @svc.port, @svc.timeout)
28
28
 
29
29
  if @req.options
30
30
  if @req.options[:cache] && @req.options[:cache][0] == :validation
@@ -44,6 +44,22 @@ module BERTRPC
44
44
  bert_response
45
45
  rescue Errno::ECONNREFUSED
46
46
  raise ConnectionError.new("Unable to connect to #{@svc.host}:#{@svc.port}")
47
+ rescue Timeout::Error
48
+ raise ReadTimeoutError.new("No response from #{@svc.host}:#{@svc.port} in #{@svc.timeout}s")
49
+ end
50
+
51
+ # Creates a socket object which does speedy, non-blocking reads
52
+ # and can perform reliable read timeouts.
53
+ #
54
+ # Raises Timeout::Error on timeout.
55
+ #
56
+ # +host+ String address of the target TCP server
57
+ # +port+ Integer port of the target TCP server
58
+ # +timeout+ Optional Integer (in seconds) of the read timeout
59
+ def connect_to(host, port, timeout = nil)
60
+ io = BufferedIO.new(TCPSocket.new(host, port))
61
+ io.read_timeout = timeout
62
+ io
47
63
  end
48
64
  end
49
- end
65
+ end
@@ -0,0 +1,28 @@
1
+ module BERTRPC
2
+ # Taken with love from memcache-client.
3
+ #
4
+ # See http://is.gd/4CWRA for the code and
5
+ # http://is.gd/4CYde for the discussion.
6
+ class BufferedIO < Net::BufferedIO # :nodoc:
7
+ BUFSIZE = 1024 * 16
8
+
9
+ if RUBY_VERSION < '1.9.1'
10
+ def rbuf_fill
11
+ begin
12
+ @rbuf << @io.read_nonblock(BUFSIZE)
13
+ rescue Errno::EWOULDBLOCK
14
+ retry unless @read_timeout
15
+ if IO.select([@io], nil, nil, @read_timeout)
16
+ retry
17
+ else
18
+ raise Timeout::Error, 'IO timeout'
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def setsockopt(*args)
25
+ @io.setsockopt(*args)
26
+ end
27
+ end
28
+ end
@@ -28,6 +28,10 @@ module BERTRPC
28
28
 
29
29
  end
30
30
 
31
+ class ReadTimeoutError < BERTRPCError
32
+
33
+ end
34
+
31
35
  class ProtocolError < BERTRPCError
32
36
  NO_HEADER = [0, "Unable to read length header from server."]
33
37
  NO_DATA = [1, "Unable to read data from server."]
@@ -1,10 +1,11 @@
1
1
  module BERTRPC
2
2
  class Service
3
- attr_accessor :host, :port
3
+ attr_accessor :host, :port, :timeout
4
4
 
5
- def initialize(host, port)
5
+ def initialize(host, port, timeout = nil)
6
6
  @host = host
7
7
  @port = port
8
+ @timeout = timeout
8
9
  end
9
10
 
10
11
  def call(options = nil)
@@ -31,4 +32,4 @@ module BERTRPC
31
32
  end
32
33
  end
33
34
  end
34
- end
35
+ end
data/lib/bertrpc.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'bert'
2
2
  require 'socket'
3
+ require 'net/protocol'
3
4
 
4
5
  require 'bertrpc/service'
5
6
  require 'bertrpc/request'
6
7
  require 'bertrpc/mod'
7
8
  require 'bertrpc/encodes'
8
9
  require 'bertrpc/action'
9
- require 'bertrpc/errors'
10
+ require 'bertrpc/errors'
11
+ require 'bertrpc/buffered_io'
data/test/action_test.rb CHANGED
@@ -49,7 +49,7 @@ class ActionTest < Test::Unit::TestCase
49
49
  @req = @svc.call
50
50
  @call = BERTRPC::Action.new(@svc, @req, :mymod, :myfun, [])
51
51
  end
52
-
52
+
53
53
  should "read and write BERT-Ps from the socket" do
54
54
  io = stub()
55
55
  io.expects(:write).with("\000\000\000\003")
@@ -57,7 +57,7 @@ class ActionTest < Test::Unit::TestCase
57
57
  io.expects(:read).with(4).returns("\000\000\000\003")
58
58
  io.expects(:read).with(3).returns("bar")
59
59
  io.expects(:close)
60
- TCPSocket.expects(:new).returns(io)
60
+ @call.expects(:connect_to).returns(io)
61
61
  assert_equal "bar", @call.transaction("foo")
62
62
  end
63
63
 
@@ -66,7 +66,7 @@ class ActionTest < Test::Unit::TestCase
66
66
  io.expects(:write).with("\000\000\000\003")
67
67
  io.expects(:write).with("foo")
68
68
  io.expects(:read).with(4).returns(nil)
69
- TCPSocket.expects(:new).returns(io)
69
+ @call.expects(:connect_to).returns(io)
70
70
  begin
71
71
  @call.transaction("foo")
72
72
  fail "Should have thrown an error"
@@ -74,14 +74,14 @@ class ActionTest < Test::Unit::TestCase
74
74
  assert_equal 0, e.code
75
75
  end
76
76
  end
77
-
77
+
78
78
  should "raise a ProtocolError when the data is invalid" do
79
79
  io = stub()
80
80
  io.expects(:write).with("\000\000\000\003")
81
81
  io.expects(:write).with("foo")
82
82
  io.expects(:read).with(4).returns("\000\000\000\003")
83
83
  io.expects(:read).with(3).returns(nil)
84
- TCPSocket.expects(:new).returns(io)
84
+ @call.expects(:connect_to).returns(io)
85
85
  begin
86
86
  @call.transaction("foo")
87
87
  fail "Should have thrown an error"
@@ -89,6 +89,20 @@ class ActionTest < Test::Unit::TestCase
89
89
  assert_equal 1, e.code
90
90
  end
91
91
  end
92
+
93
+ should "raise a ReadTimeoutError when the connection times out" do
94
+ io = stub()
95
+ io.expects(:write).with("\000\000\000\003")
96
+ io.expects(:write).with("foo")
97
+ io.expects(:read).with(4).raises(Timeout::Error)
98
+ @call.expects(:connect_to).returns(io)
99
+ begin
100
+ @call.transaction("foo")
101
+ fail "Should have thrown an error"
102
+ rescue BERTRPC::ReadTimeoutError => e
103
+ assert_equal 0, e.code
104
+ end
105
+ end
92
106
  end
93
107
  end
94
- end
108
+ end
data/test/service_test.rb CHANGED
@@ -2,10 +2,15 @@ require 'test_helper'
2
2
 
3
3
  class ServiceTest < Test::Unit::TestCase
4
4
  context "A Service" do
5
- should "be created with host and port" do
5
+ should "be creatable with host and port" do
6
6
  svc = BERTRPC::Service.new('localhost', 9941)
7
7
  assert svc.is_a?(BERTRPC::Service)
8
8
  end
9
+
10
+ should "be creatable with host, port, and timeout" do
11
+ svc = BERTRPC::Service.new('localhost', 9941, 5)
12
+ assert svc.is_a?(BERTRPC::Service)
13
+ end
9
14
  end
10
15
 
11
16
  context "A Service Instance's" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bertrpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Preston-Werner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-19 00:00:00 -07:00
12
+ date: 2009-10-27 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,6 +52,7 @@ files:
52
52
  - bertrpc.gemspec
53
53
  - lib/bertrpc.rb
54
54
  - lib/bertrpc/action.rb
55
+ - lib/bertrpc/buffered_io.rb
55
56
  - lib/bertrpc/encodes.rb
56
57
  - lib/bertrpc/errors.rb
57
58
  - lib/bertrpc/mod.rb