Skip to content

Instantly share code, notes, and snippets.

@namxam
Forked from josevalim/sample output
Last active June 11, 2016 06:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save namxam/072642f2eda3002310bc to your computer and use it in GitHub Desktop.
Save namxam/072642f2eda3002310bc to your computer and use it in GitHub Desktop.
Simple chat demo with Elixir 0.14.1
defmodule Chat.Client do
def join(server) do
client_send server, :join
end
def say(server, message) do
client_send server, { :say, message }
end
def leave(server) do
client_send server, :leave
end
# Receive a pending message from 'server' and print it
def flush(server) do
receive do
# The caret '^' is used to match against the value of 'server', it is a basic filtering based on the sender
{ ^server, {:message, message} } ->
IO.puts message
end
end
# Send 'message' to 'server' and wait for a reply
defp client_send(server, message) do
send server, { self, message }
receive do
{ ^server, response } ->
response
after
1000 ->
IO.puts "Connection to room timed out"
:timeout
end
end
end
defmodule Chat.Server do
def loop(room) do
receive do
{ pid, :join } ->
notify_all room, self, "Some user with pid #{inspect pid} joined"
send pid, { self, :ok }
updated_room = put_in room.clients, List.flatten(room.clients, [pid])
loop updated_room
{ pid, { :say, message } } ->
notify_all room , pid, "#{inspect pid}: " <> message
send pid, { self, :ok }
loop room
{ pid, :leave } ->
send pid, { self, :ok }
updated_room = put_in room.clients, List.delete(room.clients, pid)
notify_all updated_room, self, "User with pid #{inspect pid} left"
loop updated_room
end
end
# Send 'message' to all clients except 'sender'
defp notify_all(room, sender, message) do
Enum.each room.clients, fn(client_pid) ->
if client_pid != sender do
send client_pid, { self, { :message, message } }
end
end
end
end
defmodule Chat.Room do
defstruct clients: []
end
# Init a Room record with the current process
room = %Chat.Room{ clients: [self] }
# Spawn a server process
# Module name, method to call, list of arguments for that method
server_pid = spawn(Chat.Server, :loop, [room])
# Spawn another process as client
spawn fn() ->
Chat.Client.join server_pid
Chat.Client.say server_pid, "Hi!"
Chat.Client.leave server_pid
end
# And another one
spawn fn() ->
Chat.Client.join server_pid
Chat.Client.say server_pid, "What's up?"
Chat.Client.leave server_pid
end
# By this time we have 6 notifications pending
# (corresponding to three 'notify_all' calls per each client)
Enum.each 1..6, fn(_) ->
Chat.Client.flush server_pid
end
$ elixir chat_demo.ex
Some user with pid #PID<0.48.0> joined
Some user with pid #PID<0.49.0> joined
#PID<0.48.0>: Hi!
User with pid #PID<0.48.0> left
#PID<0.49.0>: What's up?
User with pid #PID<0.49.0> left
Copy link

ghost commented Jun 11, 2016

C:\Program Files (x86)\Elixir>elixir test.ex
** (CompileError) test.ex:74: cannot access struct Chat.Room, the struct was not
yet defined or the struct is being accessed in the same context that defines it

(elixir) src/elixir_map.erl:58: :elixir_map.translate_struct/4

:(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment