-module(chat). -author('Josiah Worcester '). -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).