rubarb 0.2.0 → 0.2.11

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # rubaRb
2
+ ### A Bidirectional Event Machine Based Remote Procedure Call Library for Ruby
3
+
4
+ This library uses two socket connections between a client and a server.
5
+ One is used for request / replies from the client to the server.
6
+ The other is used for remote calls made from the server to the client.
7
+
8
+ Each end publishes a single object on which methods can be called by the remote end.
9
+ All calls to the remote objects are asyncronous. Do not make any blocking calls in
10
+ the published object. Responses are return by calling the "reply" method on the responder object.
11
+
12
+ Server and Connection object may be created and started outside of EM::run,
13
+ but the Eventmachine reactor must be started somewhere in your application
14
+
15
+
16
+ ## Compilation
17
+
18
+ rake build
19
+
20
+ ## Installation
21
+
22
+ gem install rubarb
23
+
24
+ ## Server Example
25
+
26
+ class ServerApi
27
+ def time(responder)
28
+ puts "Server received time request"
29
+ responder.reply(Time.now)
30
+ end
31
+ end
32
+
33
+ EM.run do
34
+ server = Rubarb::Server.new("127.0.0.1", 9441, ServerApi.new)
35
+
36
+ connections = {}
37
+
38
+ server.start do |client|
39
+ puts "Connection Made: #{client}"
40
+ client.name do |name|
41
+ connections[name] = client
42
+ client.errback do
43
+ puts "Connection Lost: #{name}"
44
+ connections.delete(name)
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ EventMachine.add_periodic_timer(1) { puts "Connections: #{connections.keys.inspect}" }
52
+
53
+ end
54
+
55
+ ## Client Example
56
+
57
+ class ClientApi
58
+ def initialize(name)
59
+ @name = name
60
+ end
61
+ def name(responder)
62
+ responder.reply(@name)
63
+ end
64
+ end
65
+
66
+ EM::run do
67
+ connection = Rubarb::Connection.new("127.0.0.1", 9441, ClientApi.new(ARGV[0]))
68
+ connection.errback do |error|
69
+ puts ("Connection Error: #{error}")
70
+ end
71
+
72
+ connection.start do
73
+ connection.time do |response|
74
+ puts "Server Said it is: #{response.strftime("%D")}"
75
+ end
76
+
77
+ EventMachine.add_timer(20) do
78
+ puts "stopping"
79
+ connection.stop
80
+ EM::stop
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ ## Building
87
+ gem install jeweller
88
+ rake build
89
+
data/examples/client.rb CHANGED
@@ -12,7 +12,7 @@ class ClientApi
12
12
  end
13
13
 
14
14
  EM::run do
15
- connection = Rubarb::Connection.new("127.0.0.1", 9441, ClientApi.new(ARGV[0]))
15
+ connection = Rubarb::Connection.new("127.0.0.1", 9447, ClientApi.new(ARGV[0]))
16
16
  connection.errback do |error|
17
17
  puts ("Connection Error: #{error}")
18
18
  end
@@ -22,6 +22,8 @@ EM::run do
22
22
  puts "Server Said it is: #{response.strftime("%D")}"
23
23
  end
24
24
 
25
+ connection.keep_alive_time=2
26
+
25
27
  EventMachine.add_timer(20) do
26
28
  puts "stopping"
27
29
  connection.stop
data/examples/server.rb CHANGED
@@ -12,7 +12,7 @@ class ServerApi
12
12
  end
13
13
 
14
14
  EM.run do
15
- server = Rubarb::Server.new("127.0.0.1", 9441, ServerApi.new)
15
+ server = Rubarb::Server.new("127.0.0.1", 9447, ServerApi.new, Rubarb::Default::INSECURE_METHODS, 2)
16
16
 
17
17
  connections = {}
18
18
 
@@ -13,8 +13,8 @@ module Rubarb
13
13
  attr_accessor :id
14
14
  attr_accessor :on_connection
15
15
  attr_accessor :api
16
- attr_accessor :errbacks
17
16
  attr_accessor :insecure_methods
17
+ attr_accessor :parent
18
18
 
19
19
  def post_init
20
20
  @buffer = ""
@@ -24,6 +24,7 @@ module Rubarb
24
24
  Rubarb::FastMessageProtocol.install(self)
25
25
  send_data("5")
26
26
  send_data(@id)
27
+ @parent.connection_completed(self) if @parent
27
28
  end
28
29
 
29
30
  def receive_message message
@@ -36,13 +37,11 @@ module Rubarb
36
37
  end
37
38
 
38
39
  def unbind
39
- call_errbacks(ConnectionError.new)
40
+ @parent.connection_closed(self)
40
41
  end
41
42
 
42
43
  def call_errbacks(message)
43
- @errbacks.each do |e|
44
- e.call(message)
45
- end
44
+ @parent.call_errbacks(message)
46
45
  end
47
46
 
48
47
  end
@@ -54,10 +53,11 @@ module Rubarb
54
53
  attr_accessor :port
55
54
  attr_accessor :on_connection
56
55
  attr_accessor :api
57
- attr_accessor :errbacks
58
56
  attr_accessor :callback
59
57
  attr_accessor :msg_id_generator
60
58
  attr_accessor :insecure_methods
59
+ attr_accessor :parent
60
+ attr_accessor :keep_alive_time
61
61
 
62
62
  def post_init
63
63
  @buffer = ""
@@ -65,6 +65,7 @@ module Rubarb
65
65
 
66
66
  def connection_completed
67
67
  send_data("4")
68
+ @parent.connection_completed(self) if @parent
68
69
  end
69
70
 
70
71
  def receive_data data
@@ -75,17 +76,12 @@ module Rubarb
75
76
  end
76
77
 
77
78
  def unbind
78
- if @incoming_connection
79
- EM.next_tick { @incoming_connection.close_connection }
80
- else
81
- call_errbacks(ConnectionError.new)
82
- end
79
+ cancel_keep_alive
80
+ @parent.connection_closed(self)
83
81
  end
84
82
 
85
83
  def call_errbacks(message)
86
- @errbacks.each do |e|
87
- e.call(message)
88
- end
84
+ @parent.call_errbacks(message)
89
85
  end
90
86
 
91
87
  private
@@ -98,25 +94,65 @@ module Rubarb
98
94
  incoming_connection.id = @id
99
95
  incoming_connection.on_connection = @on_connection
100
96
  incoming_connection.api = @api
101
- incoming_connection.errbacks = @errbacks
102
97
  incoming_connection.insecure_methods = @insecure_methods
103
- @incoming_connection = incoming_connection
98
+ incoming_connection.parent = @parent
104
99
  end
105
100
  end
106
101
  end
107
102
  end
108
103
 
109
104
  class Connection
110
- attr_reader :remote_connection
105
+
111
106
  attr_reader :msg_id_generator
112
107
 
113
- def initialize(host, port, api, insecure_methods=Default::INSECURE_METHODS)
108
+ def remote_connection
109
+ @outgoing_connection
110
+ end
111
+
112
+ def initialize(host, port, api, insecure_methods=Default::INSECURE_METHODS, keep_alive_time = 0)
114
113
  @host = host
115
114
  @port = port
116
115
  @api = api
117
116
  @msg_id_generator = Id.new
118
117
  @errbacks = []
119
118
  @insecure_methods = insecure_methods
119
+ @connections = []
120
+ @keep_alive_time = keep_alive_time
121
+ end
122
+
123
+ def keep_alive_time=(keep_alive_time_seconds)
124
+ @keep_alive_time = keep_alive_time_seconds
125
+ if @outgoing_connection
126
+ EventMachine::schedule do
127
+ @outgoing_connection.keep_alive_time = @keep_alive_time
128
+ @outgoing_connection.reset_keep_alive
129
+ end
130
+ end
131
+ end
132
+
133
+ def close_connections
134
+ EM.next_tick do
135
+ @connections.each { |conn| conn.close_connection_after_writing }
136
+ end
137
+ end
138
+
139
+ def connection_closed(connection)
140
+ @connections.delete(connection)
141
+ if !@connections.empty?
142
+ close_connections
143
+ else
144
+ call_errbacks(ConnectionError.new)
145
+ end
146
+ end
147
+
148
+ def connection_completed(connection)
149
+ @connections << connection
150
+ end
151
+
152
+ def call_errbacks(message)
153
+ @errbacks.each do |e|
154
+ e.call(message)
155
+ end
120
156
  end
121
157
 
122
158
  def errback & block
@@ -131,10 +167,11 @@ module Rubarb
131
167
  connection.port = @port
132
168
  connection.on_connection = block
133
169
  connection.api = @api
134
- connection.errbacks = @errbacks
135
170
  connection.msg_id_generator = @msg_id_generator
136
171
  connection.insecure_methods = @insecure_methods
137
- @remote_connection = connection
172
+ connection.parent = self
173
+ connection.keep_alive_time = @keep_alive_time
174
+ @outgoing_connection = connection
138
175
  end
139
176
  rescue Exception => e
140
177
  @errbacks.each do |errback|
@@ -147,18 +184,18 @@ module Rubarb
147
184
  def method_missing(method, * args, & block)
148
185
  EventMachine::schedule do
149
186
  begin
150
- @remote_connection.remote_call(method, args, & block)
187
+ @outgoing_connection.remote_call(method, args, & block)
151
188
  rescue Exception => e
152
- @remote_connection.call_errbacks(e)
189
+ call_errbacks(e)
153
190
  end
154
191
  end
155
192
  end
156
193
 
157
194
  def stop(& callback)
158
195
  EventMachine::schedule do
159
- if @remote_connection
196
+ if @outgoing_connection
160
197
  EventMachine::next_tick do
161
- @remote_connection.close_connection
198
+ @outgoing_connection.close_connection_after_writing
162
199
  callback.call(true) if callback
163
200
  end
164
201
  else
@@ -9,10 +9,11 @@ module Rubarb
9
9
 
10
10
  def receive_message(message)
11
11
  id, method, args = unmarshal_call(message)
12
+ return unless method
12
13
  responder = Responder.new(self, id)
13
14
  begin
14
15
  raise Rubarb::InsecureMethodCallError.new(method) if @insecure_methods.include?(method)
15
- api.send(method, *[responder, *args]);
16
+ api.send(method, *[responder, *args])
16
17
  rescue Exception => e
17
18
  reply("0", e)
18
19
  end
@@ -20,6 +21,13 @@ module Rubarb
20
21
 
21
22
  def reply(id, *args)
22
23
  send_message(marshal_call(args.unshift(id)))
24
+ end
25
+
26
+ def reset_keep_alive
27
+ end
28
+
29
+ def cancel_keep_alive
30
+
23
31
  end
24
32
  end
25
33
  end
@@ -17,11 +17,26 @@ module Rubarb
17
17
  end
18
18
 
19
19
  def remote_call(method, *args, &block)
20
+ reset_keep_alive
20
21
  id = @msg_id_generator.next
21
22
  @callback ||= {}
22
23
  @callback[id] = block
23
24
  send_message(marshal_call(id, method, *args))
24
25
  end
25
26
 
27
+ def cancel_keep_alive
28
+ EventMachine::cancel_timer(@keep_alive_timer) if @keep_alive_timer
29
+ end
30
+
31
+ def reset_keep_alive
32
+ cancel_keep_alive
33
+ return if @keep_alive_time.to_i == 0
34
+
35
+ @keep_alive_timer = EventMachine::add_timer(@keep_alive_time) do
36
+ send_message(marshal_call(""))
37
+ reset_keep_alive
38
+ end
39
+ end
40
+
26
41
  end
27
42
  end
data/lib/rubarb/server.rb CHANGED
@@ -34,8 +34,8 @@ module Rubarb
34
34
 
35
35
  def stop
36
36
  EventMachine::next_tick do
37
- @remote_connection.close_connection
38
- end
37
+ @remote_connection.close_connection_after_writing
38
+ end if @remote_connection
39
39
  end
40
40
  end
41
41
 
@@ -47,7 +47,7 @@ module Rubarb
47
47
  attr_reader :insecure_methods
48
48
  attr_accessor :external_protocol
49
49
 
50
- def initialize(host, port, api, insecure_methods=Default::INSECURE_METHODS)
50
+ def initialize(host, port, api, insecure_methods=Default::INSECURE_METHODS, keep_alive_time = 0)
51
51
  @host = host
52
52
  @port = port
53
53
  @api = api
@@ -58,6 +58,16 @@ module Rubarb
58
58
  @conn_id_generator = Id.new
59
59
  @msg_id_generator = Id.new
60
60
  @insecure_methods = insecure_methods
61
+ @keep_alive_time = keep_alive_time
62
+ end
63
+
64
+ def keep_alive_time=(keep_alive_seconds)
65
+ EventMachine::schedule do
66
+ @connections.each do |c|
67
+ c.keep_alive_time = @keep_alive_time = keep_alive_seconds
68
+ c.reset_keep_alive
69
+ end
70
+ end
61
71
  end
62
72
 
63
73
  def start(& callback)
@@ -72,6 +82,7 @@ module Rubarb
72
82
  connection.unbindback = @unbind_block
73
83
  connection.insecure_methods = @insecure_methods
74
84
  connection.external_protocol = @external_protocol
85
+ connection.keep_alive_time = @keep_alive_time
75
86
  @connections << connection
76
87
  end
77
88
  rescue Exception => e
@@ -97,7 +108,7 @@ module Rubarb
97
108
  private #################################################################################
98
109
  def close_all_connections
99
110
  @connections.each do |connection|
100
- connection.close_connection
111
+ connection.close_connection_after_writing
101
112
  end
102
113
  end
103
114
 
@@ -126,6 +137,7 @@ module Rubarb
126
137
  attr_accessor :unbindback
127
138
  attr_accessor :insecure_methods
128
139
  attr_accessor :external_protocol
140
+ attr_accessor :keep_alive_time
129
141
 
130
142
  include ConnectionId
131
143
 
@@ -138,7 +150,12 @@ module Rubarb
138
150
  handshake(@buffer) if @conn_id.nil?
139
151
  end
140
152
 
153
+ def cancel_keep_alive
154
+ #will be replaced by later included modules
155
+ end
156
+
141
157
  def unbind
158
+ cancel_keep_alive
142
159
  call_errbacks(ConnectionError.new)
143
160
  @unbindback.call(self) if @unbindback
144
161
  end
@@ -5,14 +5,6 @@ require 'rubarb/connection'
5
5
 
6
6
  describe "Connection Failures" do
7
7
 
8
- before(:each) do
9
- @reactor = start_reactor
10
- end
11
-
12
- after(:each) do
13
- stop_reactor(@reactor)
14
- end
15
-
16
8
  it "should fail to connect" do
17
9
  @connection = Rubarb::Connection.new("127.0.0.1", 9441, mock("client api"))
18
10
 
@@ -8,14 +8,6 @@ require "rubarb/default"
8
8
  describe Rubarb::Connection do
9
9
  CUSTOM_INSECURE_METHODS = [:==, :===, :=~]
10
10
 
11
- before(:all) do
12
- @reactor = start_reactor
13
- end
14
-
15
- after(:all) do
16
- stop_reactor(@reactor)
17
- end
18
-
19
11
  it "has an instance of Rubarb::Id" do
20
12
  @connection = Rubarb::Connection.new("host", "port", "api")
21
13
  @connection.msg_id_generator.class.should == Rubarb::Id
@@ -49,6 +41,10 @@ describe Rubarb::Connection do
49
41
  @connection = connect(Rubarb::Connection.new("127.0.0.1", 9441, mock("client")))
50
42
  end
51
43
 
44
+ after(:each) do
45
+ sync_stop(@server)
46
+ end
47
+
52
48
  it "sets an instance of Rubarb::Id to remote_connection" do
53
49
  @connection.remote_connection.msg_id_generator.class.should == Rubarb::Id
54
50
  end
@@ -144,6 +140,10 @@ describe Rubarb::OutgoingHandler do
144
140
  remote_call(:foo, "bary")
145
141
  @sent_msg.should == marshal_call("00000001", :foo, "bary")
146
142
  end
143
+
144
+ it "should receive empty message" do
145
+ proc {receive_data("")}.should_not raise_error
146
+ end
147
147
  end
148
148
 
149
149
  describe Rubarb::IncomingHandler do
@@ -177,11 +177,16 @@ describe Rubarb::IncomingHandler do
177
177
 
178
178
  it "should errback if ids do not match" do
179
179
  errback_msg = false
180
- @errbacks = [Proc.new { |error| errback_msg = error.message }]
180
+ @parent = mock("parent")
181
+ @parent.should_receive(:call_errbacks) do |error|
182
+ error.message.should == "Handshake Failure"
183
+ end
184
+
185
+ @parent.should_receive(:connection_completed).with(self)
186
+
181
187
  @id = "00000001"
182
188
 
183
189
  connection_completed
184
190
  receive_message("00000004")
185
- errback_msg.should == "Handshake Failure"
186
191
  end
187
192
  end