Quantcast
Channel: Hacker News
Viewing all articles
Browse latest Browse all 25817

Elixir and Ruby can talk to each other using Erlix

$
0
0

This article describes another way, how Elixir and Ruby can talk to each other. We will use Erlix this time. This method makes Ruby process act like the Erlang node, witch is connected to Erlang VM over the network.

We will make some kind of chat between Ruby and Elixir. There will be two separate parts. Elixir and Ruby project.

Elixir Project

We need to create new Elixir project.

$ mix new chat_ex
$ cd chat_ex

And add mod to application:

We need a little bit configuration

@process_name :ex_rb
@ruby_process_name :ruby

@process_name is a name of process that will receive messages from Ruby
@ruby_process_name is the name of the process, that will store PID of the process that ruby send just after connecting to the node.

Ok, write a function that will be executed when out application start.

def start(_type, _args) do
pid = spawn(&receive_messages/0)
Process.register(pid, @process_name)
read_line
end

When our application starts we need to spawn a process that will receive messages from ruby and register it with a name so ruby can locate it. Also, we need to start a loop that will read messages from the console and send it to Ruby.

We need two types of messages. One message will send us Ruby process PID, we will need to save it for future usage. And second one that will receive our messages.

def receive_messages do
receive do
# message with process pid
{:register, pid} ->
IO.puts "Ruby connected!"
Agent.start_link(fn -> pid end, name: @ruby_process_name)
# message with message
{:message, message} ->
IO.puts "Message from ruby: #{message}"
end
receive_messages
end

Nice, while register message will come, we start a new Agent that will store Ruby process PID. When we receive a message with text, we will just display it on the console.

What about reading from the console ? Right! The read_line function will do that.

def read_line do
case IO.read(:stdio, :line) do
:eof -> :ok
{:error, reason} -> IO.puts "Error: #{reason}"
data ->
if Process.registered |> Enum.member?(@ruby_process_name) do
ruby = Agent.get(@ruby_process_name, &(&1))
send ruby, data
end
end
read_line
end

When we will receive any line from STDIO, we will send it to our Ruby process. We can get pid of this process from Agent, and send our data.

We’re finished! Our module looks like this:

We’ve got all we need, let’s move to Ruby Project!

Ruby Project

Also in Ruby, we need to create a Ruby project.

$ mkdir chat_rb
$ cd chat_rb
$ bundle init

Add erlix gem to Gemfile:

# frozen_string_literal: true
source 'https://rubygems.org'
gem 'erlix'

and bundle it.

$ bundle

Now we’re creating the main file of our application. First, we need to require bundler to include all dependencies. So let’s create file named main.rb

#!/usr/bin/ruby
require 'bundler'
Bundler.require

Next, we will need a few constants:

COOKIE = 'cookie'
HOST = `hostname -s`.strip
NODE_NAME = 'ruby'
DST_NODE_NAME = 'elixir'
DST_NODE = "#{DST_NODE_NAME}@#{HOST}"
DST_PROC = 'ex_rb'

So, let’s describe them: 
- COOKIE is a name of Erlang cookie. Nodes to communicate to each other have to have the same name.
- HOST host that we will connect to, in this case, is our computer
- NODE_NAME name of node written in ruby
- DST_NODE_NAME name of node that we will connect to
- DST_NODE full name of node that we connect to 
- DST_PROC name of process that will receive our messages

We’ve got all information needed to connect.

Erlix::Node.init(NODE_NAME, COOKIE)
connection = Erlix::Connection.new(DST_NODE)

Fist line will initialize our node, next one will connect to Erlang node. Just after connection we need to send registration message, so Elixir will know that we’re connected, and save out PID.

connection.esend(
DST_PROC,
Erlix::Tuple.new([
Erlix::Atom.new('register'),
Erlix::Pid.new(connection)
])
)

We’re registered, next, we need a thread that will receive messages from Elixir, and print them on the console.

Thread.new do
while true do
message = connection.erecv
puts 'Message from elixir: #{message.message.data}'
end
end

OK, the missing part is a loop that reads data from the console and sends them to Elixir.

while true
input = STDIN.gets
connection.esend(
DST_PROC,
Erlix::Tuple.new([
Erlix::Atom.new("message"),
Erlix::Atom.new(input)
])
)
end

And we’re done! Our final script will look like this:

Connecting…

We need to start our Elixir application with parameters that we used in Ruby project.

$ cd chat_ex
$ elixir --sname elixir --cookie cookie -S mix run

Compiling… Done! Elixir node run, now Ruby.

$ cd chat_rb
$ ruby main.rb

Great! Connected to …@… nice, take a look at Elixir console… Ruby connected Wow it works. Let’s send some messages. On Elixir console just type, for example, hello from elixir end hit enter! What is on Ruby console ? Our message! Message from elixir: hello from elixir! Now from Ruby. Type on ruby console hello from ruby again hit enter. What is on elixir console ? Right: Message from ruby: hello from ruby! We’re connected. Another great success!


Viewing all articles
Browse latest Browse all 25817

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>