Skip to content

Instantly share code, notes, and snippets.

@taiansu
Forked from alco/chat_demo.ex
Created August 6, 2014 19:54
Show Gist options
  • Save taiansu/626bd9f081c3e02f227e to your computer and use it in GitHub Desktop.
Save taiansu/626bd9f081c3e02f227e to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment