64 lines
2.0 KiB
Erlang
64 lines
2.0 KiB
Erlang
-module(chat).
|
|
|
|
-export([start/0, start/1]).
|
|
|
|
-record(client, {name=none, socket=none}).
|
|
|
|
start() -> start(8080).
|
|
start(Port) ->
|
|
register(server, spawn(fun() -> server() end)),
|
|
{ok, LSocket} = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]),
|
|
accept(LSocket).
|
|
|
|
% main loop for message dispatcher
|
|
server() -> server([]).
|
|
server(Clients) ->
|
|
receive
|
|
{join, Client=#client{name = Name, socket = Socket}} ->
|
|
self() ! {say, Socket, "has joined." ++ [10, 13]},
|
|
server(Clients ++ [Client]);
|
|
{leave, Socket} ->
|
|
{value, #client{name = Name}, List} = lists:keytake(Socket, 3, Clients),
|
|
self() ! {say, none, Message = "has left."},
|
|
server(List);
|
|
{say, Socket, Data} ->
|
|
{value, #client{name = From}, List} = lists:keytake(Socket, 3, Clients),
|
|
Message = From ++ " : " ++ Data,
|
|
lists:map(fun(#client{socket = S}) ->
|
|
gen_tcp:send(S, Message)
|
|
end, List)
|
|
end,
|
|
server(Clients).
|
|
|
|
% accepts connections then spawns the client handler
|
|
accept(LSocket) ->
|
|
{ok, Socket} = gen_tcp:accept(LSocket),
|
|
spawn(fun() -> connecting(Socket) end),
|
|
accept(LSocket).
|
|
|
|
% when client is first connect send prompt for user name
|
|
connecting(Socket) ->
|
|
gen_tcp:send(Socket, "What is your name? "),
|
|
case listen(Socket) of
|
|
{ok, N} ->
|
|
Name = binary_to_list(N),
|
|
server ! {join, #client{name = lists:sublist(Name, 1, length(Name) - 2), socket = Socket} },
|
|
client(Socket);
|
|
_ -> ok
|
|
end.
|
|
|
|
% main client loop that listens for data
|
|
client(Socket) ->
|
|
case listen(Socket) of
|
|
{ok, Data} ->
|
|
server ! {say, Socket, binary_to_list(Data)},
|
|
client(Socket);
|
|
_ -> server ! {leave, Socket}
|
|
end.
|
|
|
|
% utility function that listens for data on a socket
|
|
listen(Socket) ->
|
|
case gen_tcp:recv(Socket, 0) of
|
|
Response -> Response
|
|
end.
|