Skip to content

Commit 8873f04

Browse files
committed
Refactored - Hid the EM calls
1 parent 608e4cb commit 8873f04

File tree

3 files changed

+121
-112
lines changed

3 files changed

+121
-112
lines changed

README.textile

Lines changed: 39 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ h2. rinterface: Ruby to Erlang client
22

33
rinterface is a pure Ruby client that can send RPC calls to an Erlang node. It's very much a work in progress.
44

5-
65
h3. Requirements
76

87
* Erlang 12B-5
@@ -12,114 +11,71 @@ h3. Requirements
1211

1312
h3. Try it out
1413

15-
1. Open a terminal, Cd into the test directory and run:
14+
1. Open a terminal, Cd into the test directory and run:
1615
'make'
1716
'make run'
18-
this will start the erlang node named 'math'
17+
18+
This will start the erlang node named 'math'
1919

20-
2. Open another terminal, and run: 'ruby sample.rb'
20+
2. Open another terminal, and run: 'ruby sample.rb'
2121

2222
h3. How to use?
2323

24-
See 'sample.rb' for an example:
25-
24+
In your Ruby code, make a call to the Erlang node like this:
2625
<pre>
2726
<code>
28-
EM.run do
29-
# Connect to epmd to get the port of 'math'. 'math' is the -sname of the erlang node
30-
epmd = EpmdConnection.lookup_node("math")
31-
epmd.callback do |port|
32-
puts "got the port #{port}"
33-
34-
# make the rpc call to 'math' on port for mod 'math_server' on fun 'add' with args
35-
node = Node.rpc_call("math",port.to_i,"math_server","add",[10,20])
36-
node.callback{ |result|
37-
puts "Sum is: #{result}"
38-
EM.stop
39-
}
40-
41-
node.errback{ |err|
42-
puts "Error: #{err}"
43-
EM.stop
44-
}
45-
end
46-
47-
epmd.errback do |err|
48-
puts "Error: #{err}"
49-
EM.stop
50-
end
51-
end
52-
</code>
53-
</pre>
27+
# Erlang::Node(nodename,module,function,args) => [:ok,Response] | [:badprc,Reason]
5428

29+
r = Erlang::Node.rpc("math","math_server","add",[10,20])
5530

56-
h3. So you wanna call Erlang from your Rails app...
57-
58-
Here's a quick and simple example. Make sure you put the rinterface lib into RAILS_ROOT/lib and start the math_server in 'test'
59-
60-
First we'll wrap rinterface in a class to call from Rails:
31+
if r[0] == :badrpc
32+
puts "Got and Error. Reason #{r[1]}"
33+
else
34+
puts "Success: #{r[1]}"
35+
end
36+
</code>
37+
</pre>
6138

62-
models/math_service.rb
39+
Where:
40+
* 'math' is the node name (the -sname of the Erlang node)
41+
* 'math_server' is the name of the module
42+
* 'add' is the funtion to call
43+
* args is an array of arguments to pass to the function
6344

45+
The result will always be an Array of the form:
6446
<pre>
6547
<code>
66-
require 'lib/rinterface'
67-
68-
class MathService
69-
include Erlang
70-
attr_accessor :result
48+
[:ok,Response] where Response is the result from the Erlang
49+
50+
or
7151

72-
def self.sum(args)
73-
s = self.new
74-
s.call_erlang(args)
75-
s.result
76-
end
77-
78-
def initialize
79-
@result = 0
80-
end
81-
82-
def call_erlang(args)
83-
EM.run do
84-
# Connect to epmd to get the port of 'math'.
85-
# 'math' is the -sname of the erlang node
86-
epmd = EpmdConnection.lookup_node("math")
87-
epmd.callback do |port|
88-
89-
# make the rpc call to 'math' on port for mod 'math_server' on
90-
# fun 'add' with args
91-
node = Node.rpc_call("math",port.to_i,"math_server","add",args)
92-
node.callback{ |result|
93-
@result = result
94-
EM.stop
95-
}
96-
97-
node.errback{ |err|
98-
EM.stop
99-
}
100-
end
101-
102-
epmd.errback do |err|
103-
EM.stop
104-
end
105-
end
106-
end
107-
108-
end
52+
[:badrpc,Reason] where Reason is the 'why' it failed
10953
</code>
11054
</pre>
11155

112-
Now here's the controller:
56+
h3. So you wanna call Erlang from your Rails app...
11357

114-
controllers/math_controller.rb
58+
Here's a quick and simple example. Make sure you put the rinterface lib into RAILS_ROOT/lib and start the math_server in 'test'
59+
60+
In the controller:
11561

62+
controllers/math_controller.rb
11663
<pre>
11764
<code>
65+
require 'lib/rinterface'
66+
11867
class MathController < ApplicationController
11968
def index
12069
a = params[:a]
12170
b = params[:b]
122-
@result = MathService.sum([a.to_i,b.to_i])
71+
r = Erlang::Node.rpc("math","math_server","add",[a.to_i,b.to_i])
72+
73+
if r[0] == :badrpc
74+
@result = "Error"
75+
else
76+
@result = r[1]
77+
end
78+
12379
end
12480
end
12581
</code>

lib/erlang/node.rb

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,68 @@
55
# - makes the RPC call
66
#
77
module Erlang
8-
class Node < EM::Connection
8+
class Node
9+
attr_reader :result
10+
11+
def initialize
12+
@result = nil
13+
end
14+
15+
def self.rpc(node,mod,fun,args)
16+
n = self.new
17+
setup = proc{ n.do_connect(node,mod,fun,args) }
18+
19+
if EM.reactor_running?
20+
setup.call
21+
else
22+
EM.run(&setup)
23+
end
24+
n.result
25+
end
26+
27+
def do_connect(node,mod,fun,args)
28+
epmd = EpmdConnection.lookup_node(node)
29+
epmd.callback do |port|
30+
conn = NodeConnection.rpc_call(node,port,mod,fun,args) do |c|
31+
c.destnode = node
32+
c.mod = mod
33+
c.fun = fun
34+
c.args = args
35+
c.port = port
36+
c.myname = build_nodename
37+
c.cookie = get_cookie
38+
end
39+
conn.callback do |r|
40+
# Check for bad rpc response
41+
# this is where I miss the patten matching in Erlang
42+
if r.is_a?(Array)
43+
if !r.empty? && r[0] == :badrpc
44+
@result = [:badrpc,r[1]]
45+
else
46+
@result = [:ok,r]
47+
end
48+
else
49+
@result = [:ok,r]
50+
end
51+
EM.stop
52+
end
53+
conn.errback do |err|
54+
# never called??
55+
@result = [:badrpc,err]
56+
EM.stop
57+
end
58+
end
59+
epmd.errback do |err|
60+
# return bad RPC no port found (0)
61+
@result = [:badrpc,"no port found for service"]
62+
EM.stop
63+
end
64+
end
65+
66+
end
67+
68+
69+
class NodeConnection < EM::Connection
970
include EM::Deferrable
1071

1172
attr_accessor :host,:myname,:destnode,:port,:cookie,:mod,:fun,:args
@@ -27,6 +88,7 @@ def self.rpc_call(node,port,mod,fun,args)
2788
end
2889
end
2990

91+
3092
# Get the Cookie from the home directory
3193
def self.get_cookie
3294
# ... I did it all for the cookie, come on the cookie ...
@@ -67,11 +129,13 @@ def handle_any_response
67129
decoder.read_any
68130
# read the message
69131
result = decoder.read_any
70-
puts "Raw Response: #{result.inspect}"
132+
#puts "Raw Response: #{result.inspect}"
133+
set_deferred_success result[1]
71134
else
135+
# This seems to never happen...always 'p'
72136
result = decoder.read_any
137+
set_deferred_failure result
73138
end
74-
set_deferred_success result[1]
75139
end
76140

77141
def send_name
@@ -140,6 +204,7 @@ def make_challenge(her_challenge)
140204
encoder.out.string
141205
end
142206

207+
# Handshake complete...send the RPC
143208
def receive_challenge_ack(packet_size,decoder)
144209
@responder = :handle_any_response
145210
call_remote

sample.rb

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,19 @@
11
require 'lib/rinterface'
22

33

4-
# Example of connecting to an Erlang node and making an RPC call
5-
include Erlang
4+
# Try different responses...
65

7-
EM.run do
8-
# Connect to epmd to get the port of 'math'. 'math' is the -sname of the erlang node
9-
epmd = EpmdConnection.lookup_node("math")
10-
epmd.callback do |port|
11-
puts "got the port #{port}"
12-
13-
# make the rpc call to 'math' on port for mod 'math_server' on fun 'add' with args
14-
node = Node.rpc_call("math",port.to_i,"math_server","add",[10,20])
15-
node.callback{ |result|
16-
puts "Sum is: #{result}"
17-
EM.stop
18-
}
19-
20-
node.errback{ |err|
21-
puts "Error: #{err}"
22-
EM.stop
23-
}
24-
end
25-
26-
epmd.errback do |err|
27-
puts "Error: #{err}"
28-
EM.stop
29-
end
30-
end
6+
# Bad rpc. Try to call the wrong service
7+
r = Erlang::Node.rpc("math","matx_server","add",[10,20])
8+
puts "Got: #{r.inspect}"
9+
10+
puts "--------"
11+
# No Port for Service. Can't find a port for 'ath'
12+
r = Erlang::Node.rpc("ath","matx_server","add",[10,20])
13+
puts "Got: #{r.inspect}"
14+
15+
puts "--------"
16+
# Good call
17+
r = Erlang::Node.rpc("math","math_server","add",[10,20])
18+
puts "Got: #{r.inspect}"
3119

0 commit comments

Comments
 (0)