rendered paste body-module(chat).
-author('Josiah Worcester <josiahw@gmail.com>').
-export([listen/1]).
-define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr, true}]).
listen(Port) ->
{ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
Server = spawn(fun () -> server([]) end),
accept(LSocket, Server).
accept(LSocket, Server) ->
{ok, Socket} = gen_tcp:accept(LSocket),
spawn(fun () -> client(Socket, Server) end),
accept(LSocket, Server).
client(Socket, Server) ->
gen_tcp:send(Socket, "Your name?\r\n"),
{ok, NameB} = gen_tcp:recv(Socket, 0),
Name = NameB -- "\r\n",
case Name of
"SERVER" ->
gen_tcp:send(Socket, "Invalid name.\r\n"),
client(Socket,Server);
_ ->
Messenger = spawn(fun () -> messageLoop(Socket) end),
Messenger ! {message, ("Hello, " ++ Name ++ "\r\n")},
Client = {Messenger, Name},
Server ! {newclient, Client},
tcpLoop(Socket, Server, Client)
end.
messageLoop(Socket) ->
receive
{message, Message} ->
gen_tcp:send(Socket,Message),
messageLoop(Socket)
end.
tcpLoop(Socket, Server, Messenger) ->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
case Data of
"/disconnect\r\n" ->
disconnect(Socket, Server, Messenger);
_ ->
Server ! {broadcast, Data, Messenger},
tcpLoop(Socket, Server, Messenger)
end;
{error, closed} ->
disconnect(Socket, Server, Messenger)
end.
disconnect(Socket, Server, Messenger) ->
Server ! {disconnect, Messenger},
{MessengerPID, _} = Messenger,
exit(MessengerPID, kill),
gen_tcp:close(Socket).
server(Clients) ->
receive
{newclient, Client} ->
NewClients = [Client | Clients],
serverMessage(NewClients, Client, "has joined.\r\n"),
server(NewClients);
{disconnect, Client} ->
NewClients = lists:delete(Client, Clients),
serverMessage(NewClients, Client, "has disconnected.\r\n"),
server(NewClients);
{broadcast, Message, Source} ->
broadcast(Clients, Source, Message),
server(Clients)
end.
serverMessage(Clients, Client, Message) ->
Server = {{}, "SERVER"},
{_, Name} = Client,
broadcast(Clients, Server, "\"" ++ Name ++ "\" " ++ Message).
broadcast(Clients, Source, Message) ->
{SourcePID, Name} = Source,
Output = lists:append([Name, ": ", Message ]),
io:fwrite(Output),
lists:foreach(fun ({ClientPID, _}) when ClientPID /= SourcePID ->
ClientPID ! {message, Output};
(_) -> ok
end, Clients).