rubarb 0.2.0 → 0.2.11
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/README.md +89 -0
- data/examples/client.rb +3 -1
- data/examples/server.rb +1 -1
- data/lib/rubarb/connection.rb +61 -24
- data/lib/rubarb/incoming_connection.rb +9 -1
- data/lib/rubarb/outgoing_connection.rb +15 -0
- data/lib/rubarb/server.rb +21 -4
- data/spec/rubarb/connection_failure_spec.rb +0 -8
- data/spec/rubarb/connection_spec.rb +15 -10
- data/spec/rubarb/incoming_connection_spec.rb +6 -0
- data/spec/rubarb/integration_spec.rb +67 -8
- data/spec/rubarb/outgoing_connection_spec.rb +4 -0
- data/spec/rubarb/server_failure_spec.rb +124 -122
- data/spec/rubarb/server_spec.rb +4 -10
- data/spec/spec_helper.rb +28 -7
- metadata +79 -102
- data/.gitignore +0 -7
- data/README +0 -77
- data/Rakefile +0 -51
- data/VERSION +0 -1
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",
|
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
data/lib/rubarb/connection.rb
CHANGED
@@ -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
|
-
|
40
|
+
@parent.connection_closed(self)
|
40
41
|
end
|
41
42
|
|
42
43
|
def call_errbacks(message)
|
43
|
-
@
|
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
|
-
|
79
|
-
|
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
|
-
@
|
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
|
-
|
98
|
+
incoming_connection.parent = @parent
|
104
99
|
end
|
105
100
|
end
|
106
101
|
end
|
107
102
|
end
|
108
103
|
|
109
104
|
class Connection
|
110
|
-
|
105
|
+
|
111
106
|
attr_reader :msg_id_generator
|
112
107
|
|
113
|
-
def
|
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
|
-
|
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
|
-
@
|
187
|
+
@outgoing_connection.remote_call(method, args, & block)
|
151
188
|
rescue Exception => e
|
152
|
-
|
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 @
|
196
|
+
if @outgoing_connection
|
160
197
|
EventMachine::next_tick do
|
161
|
-
@
|
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.
|
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.
|
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
|
-
@
|
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
|