Communicating from Ruby to Erlang
16 November 2008
I’ve been working pretty hard on PoolParty lately. PoolParty is a combination of ruby and erlang and gives full access to the cloud using a console.
pool console
I’m going to show you how I implemented the console, which is a container for irb and lightweight socket communication to the messenger written in erlang.
I’ll assume that you know enough about erlang to get through the code as beginning erlang is out of scope for this tutorial.
First, let’s look at the erlang messenger
-module (server).
-export (start/0).
start() ->
{ok, LSock} = gen_tcp:listen(5678, [binary, {packet, 0}, {active, false}]),
active(LSock).
accept(Socket) ->
{ok, Sock} = gen_tcp:accept(Socket),
spawn(fun() -> loop(do_recv(Sock)) end),
accept(Socket).
do_recv(Sock) ->
case gen_tcp:recv(Sock, 0) of
{ok, B} ->
[Meth|Args] = string:tokens(erlang:binary_to_list(Data), " "),
case Meth of
{time} ->
{Date={Year,Month,Day},Time={Hour,Minutes,Seconds}}
= erlang:localtime(),
IntString =
[ erlang:integer_to_list(A) || A <- [Hour, Minutes, Seconds] ],
ResponseString = lists:append(IntString),
gen_tcp:send(Sock, ResponseString),
do_recv(Sock);
_ ->
gen_tcp:send(Sock, B),
do_recv(Sock);
end;
{error, closed} ->
{ok, list_to_binary(Bs)}
end.
Now we have a spawning server that spawns off responses to respond to the requests that comes into the server, handles them and sends back their responses to the caller (using gen_tcp). In our case, we’ll be calling the contrived time method that will send us back the hour minutes and seconds
We can start the server like this
auser ~ $ erl
Erlang (BEAM) emulator version 5.6.2 [source] [async-threads:0] [kernel-poll:false]
Eshell V5.6.2 (abort with ^G)
1> c(server.erl).
2> server:start(7050).
Now that we have the server running, let’s get our ruby side talking. Our gen_tcp-based server above starts a listener at the port 5678, sounds like something we can hook up using ruby’s TCPSocket class. Which is exactly what we will do:
require "socket"
module Messenger
def initialize(host="localhost", port=5678)
@host = host;@port = port
end
def with_socket(&block)
begin
socket = TCPSocket.open(@host, @port)
out = yield(socket)
socket.close
out
rescue Exception => e
end
end
def call!(msg="time")
with_socket do |sock|
sock.send(msg, 0)
@str = sock.recv(2000)
end
@str
end
def cast!(msg="list")
with_socket do |sock|
sock.send(msg, 0)
end
end
end
So we can call call! on any class that includes Messenger and it will send the data using a socket we open with the with_socket method. Upon sending the message, we also immediately open a socket to listen for the response. If we just want to send a message to the erlang messenger, then we can just call cast! with the message we want to send
class Test
include Messenger
end
@t = Test.new
@t.call!("time")
That about wraps up this edition of inside PoolParty, check out Labs at CitrusByte for more information about PoolParty.
Have fun! -Ari
Comments
blog comments powered by Disqus