Skip to content

Instantly share code, notes, and snippets.

@archan937
Last active Feb 28, 2019
Embed
What would you like to do?
Alkmaar Elixir Meetup (20-06-2018)

Alkmaar Elixir Meetup demo (20-06-2018)

A simple host and client script written in Elixir. Hosting a little Elixir quiz.

Running locally (on your own computer)

Run the following in two Terminal windows:

iex -r host.ex
iex -r client.ex

Running within a LAN

Run the following in two Terminal windows:

iex -r host.lan.ex
iex -r client.lan.ex

Please note that you need to correct the @host module attribute within the client script file.

Also, when encountering Protocol ‘inet_tcp’: register/listen error: econnrefused please run the following command first.

epmd -daemon

Enjoy!

# epmd -daemon
# iex -r client.ex
defmodule Client do
@host :host
@client :client
@key "NAME"
def run() do
Process.register(self(), @client)
Node.start(@client, :shortnames)
Node.connect(hostnode())
send_message(:hello)
loop()
end
defp hostnode() do
{:ok, hostname} = :inet.gethostname()
String.to_atom("#{@host}@#{hostname}")
end
defp loop() do
receive do
{question, :ask} ->
question
|> ask()
|> send_message()
{message, :listen} ->
IO.puts message
end
loop()
end
defp ask(question) do
"#{question} "
|> IO.gets()
|> String.trim()
end
defp send_message(message) do
destination = {@host, hostnode()}
message = {Node.self(), {name(), message}}
send(destination, message)
end
defp name() do
case System.get_env(@key) do
nil ->
name = ask("What is your name?")
:ok = System.put_env(@key, name)
name
name -> name
end
end
end
Client.run()
# epmd -daemon
# iex -r client.lan.ex
defmodule Client do
@host :host
@client :client
@key "NAME"
@hostnode String.to_atom("#{@host}@192.168.0.24")
def run() do
Process.register(self(), :client)
[@client, ip()]
|> Enum.join("@")
|> String.to_atom()
|> Node.start(:longnames)
Node.set_cookie(:cookie)
Node.connect(@hostnode)
send_message(:hello)
loop()
end
defp ip() do
{:ok, [{ip, _, _} | _]} = :inet.getif()
ip
|> Tuple.to_list()
|> Enum.join(".")
end
defp loop() do
receive do
{question, :ask} ->
question
|> ask()
|> send_message()
{message, :listen} ->
IO.puts message
end
loop()
end
defp ask(question) do
"#{question} "
|> IO.gets()
|> String.trim()
end
defp send_message(message) do
destination = {@host, @hostnode}
message = {Node.self(), {name(), message}}
send(destination, message)
end
defp name() do
case System.get_env(@key) do
nil ->
name = ask("What is your name?")
:ok = System.put_env(@key, name)
name
name -> name
end
end
end
Client.run()
# iex -r host.ex
defmodule Host do
@host :host
@client :client
@questions [
["Who created Elixir? José ...?", "Valim"],
["In which year did Elixir first appear?", "2011"],
["What lies underneath Elixir?", "Erlang"],
["Did you enjoy the presentation?", "Yes"]
]
def run() do
Process.register(self(), @host)
Node.start(@host, :shortnames)
loop()
end
defp loop() do
index = 0
ask(index)
loop(index)
end
defp loop(index) do
receive do
{client, {name, :hello}} ->
greet(index, client, name)
{client, {name, answered}} ->
check(index, client, name, answered)
end
|> case do
:next ->
index = index + 1
ask(index)
index
_ -> index
end
|> loop()
end
defp greet(index, client, name) do
IO.puts("Hello, #{name}!")
ask(index, client)
end
defp ask(index) do
IO.puts(question(index))
Enum.each(Node.list(), fn(client) ->
ask(index, client)
end)
end
defp ask(index, client) do
send_message(client, {question(index), :ask})
end
defp check(index, client, name, answered) do
answer = answer(index)
{status, {reply, _} = message} =
case answered do
^answer ->
{:next, {"Correct, #{name}!", :listen}}
_ ->
{:idle, {"Ah, #{name}. Try again!", :ask}}
end
IO.puts("#{reply} #{inspect answered}")
send_message(client, message)
status
end
defp question(index) do
@questions
|> Enum.at(index)
|> Enum.at(0)
end
defp answer(index) do
@questions
|> Enum.at(index)
|> Enum.at(1)
end
defp send_message(client, message) do
destination = {@client, client}
send(destination, message)
end
end
Host.run()
# iex -r host.lan.ex
defmodule Host do
@host :host
@client :client
@questions [
["Who created Elixir? José ...?", "Valim"],
["In which year did Elixir first appear?", "2011"],
["What lies underneath Elixir?", "Erlang"],
["Did you enjoy the presentation?", "Yes"]
]
def run() do
Process.register(self(), @host)
[@host, ip()]
|> Enum.join("@")
|> String.to_atom()
|> Node.start(:longnames)
Node.set_cookie(:cookie)
IO.inspect(Node.self())
loop()
end
defp ip() do
{:ok, [{ip, _, _}, _]} = :inet.getif()
ip
|> Tuple.to_list()
|> Enum.join(".")
end
defp loop() do
index = 0
ask(index)
loop(index)
end
defp loop(index) do
receive do
{client, {name, :hello}} ->
greet(index, client, name)
{client, {name, answered}} ->
check(index, client, name, answered)
end
|> case do
:next ->
index = index + 1
ask(index)
index
_ -> index
end
|> loop()
end
defp greet(index, client, name) do
IO.puts("Hello, #{name}!")
ask(index, client)
end
defp ask(index) do
IO.puts(question(index))
Enum.each(Node.list(), fn(client) ->
ask(index, client)
end)
end
defp ask(index, client) do
send_message(client, {question(index), :ask})
end
defp check(index, client, name, answered) do
answer = answer(index)
{status, {reply, _} = message} =
case answered do
^answer ->
{:next, {"Correct, #{name}!", :listen}}
_ ->
{:idle, {"Ah, #{name}. Try again!", :ask}}
end
IO.puts("#{reply} #{inspect answered}")
send_message(client, message)
status
end
defp question(index) do
@questions
|> Enum.at(index)
|> Enum.at(0)
end
defp answer(index) do
@questions
|> Enum.at(index)
|> Enum.at(1)
end
defp send_message(client, message) do
destination = {@client, client}
send(destination, message)
end
end
Host.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment