Skip to content

Instantly share code, notes, and snippets.

@dry
Forked from josevalim/sample output
Last active December 11, 2015 16:19
Show Gist options
  • Save dry/4627016 to your computer and use it in GitHub Desktop.
Save dry/4627016 to your computer and use it in GitHub Desktop.
defmodule Chat.Client do
# In all of the following functions 'server' stands for the server's pid
def join({server, name}) do
send server, {name, :join, ""}
end
def say({server, name, message}) do
send server, {name, :say, message}
end
def leave({server, name}) do
send server, {name, :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
# Notice how this function is declared using 'defp' meaning
# it's private and can only be called inside this module
defp send(server, {name, action, message}) do
server <- { Process.self, {name, action, message} }
receive do
{ ^server, response } ->
response
after
1000 ->
IO.puts "Connection to room timed out"
:timeout
end
end
end
defmodule Chat.Server do
# A Room record acts as a reference to 'this' or 'self' in other langs
defrecord Room, clients: []
# The main receive loop
def msg_loop(room) do
receive do
{pid, {name, :join, _} } ->
notify_all room, Process.self, "#{name} with pid #{inspect pid} joined"
pid <- { Process.self, :ok }
# The 'prepend_clients' function is generated automatically.
# See section 4.1.1 in http://elixir-lang.org/getting_started/4.html
msg_loop room.update_clients(fn(clients) -> List.concat([pid], clients) end)
{pid, {name, :say, message}} ->
notify_all room, pid, "#{name} says: " <> message
pid <- { Process.self, :ok }
msg_loop room
{pid, {name, :leave, _}} ->
pid <- { Process.self, :ok }
# 'update_clients' is another automatically generated function
new_room = room.update_clients(fn(clients) -> List.delete(clients, pid) end)
notify_all new_room, Process.self, "#{name} with pid #{inspect pid} left"
msg_loop new_room
end
end
# Send 'message' to all clients except 'sender'
defp notify_all({Room, clients}, sender, message) do
Enum.each clients, fn(pid) ->
if pid != sender do
pid <- { Process.self, {:message, message} }
end
end
end
end
# Init a Room record with the current process
room = Chat.Server.Room.new(clients: [Process.self])
# Spawn a server process
server_pid = spawn fn() -> Chat.Server.msg_loop room end
# Spawn another process as client
spawn fn() ->
Chat.Client.join {server_pid, "John"}
Chat.Client.say {server_pid, "John", "Hi!"}
Chat.Client.leave {server_pid, "John"}
end
# And another one
spawn fn() ->
Chat.Client.join {server_pid, "Dave"}
Chat.Client.say {server_pid, "Dave", "What's up?"}
Chat.Client.leave {server_pid, "Dave"}
end
# By this time we have 6 notifications pending
# (corresponding to three 'notify_all' calls per each client)
Enum.map :lists.seq(1, 6), fn(_count) ->
Chat.Client.flush server_pid
end
$ elixir chat_demo.ex
Some user with pid <0.41.0> joined
Some user with pid <0.42.0> joined
<0.41.0>: Hi!
User with pid <0.41.0> left
<0.42.0>: What's up?
User with pid <0.42.0> left
Copy link

ghost commented Jul 22, 2013

ok wtf error is this:

Mon 07/22/2013 20:53:01.50 s:\workspace.elixir.2013>elixir chat_demo.ex
** (BadArityError) bad arity error: #Function<elixir_compiler_0.3.21665362
> called with [1]
    s:/workspace.elixir.2013/elixir/lib/elixir/lib/enum.ex:298: Enum."-eac
h/2-fun-0-"/3
    s:/workspace.elixir.2013/elixir/lib/elixir/lib/range.ex:47: Range.Iter
ator.Number.do_reducer_up/4
    s:/workspace.elixir.2013/elixir/lib/elixir/lib/enum.ex:297: Enum.each/
2
    src/elixir_compiler.erl:65: :elixir_compiler."-eval_forms/4-fun-0-"/7
    src/elixir_compiler.erl:64: :elixir_compiler.eval_forms/4
    src/elixir_compiler.erl:32: :elixir_compiler.quoted/2
    s:/workspace.elixir.2013/elixir/lib/elixir/lib/code.ex:281: Code.requi
re_file/2
    s:/workspace.elixir.2013/elixir/lib/elixir/lib/kernel/cli.ex:288: Kern
el.CLI.process_command/2

Copy link

ghost commented Jul 22, 2013

oops wrong gist, I meant to post on mine :) ignore that (&sorry)

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