-
-
Save taiansu/626bd9f081c3e02f227e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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