diff options
| -rw-r--r-- | server.erl | 82 | 
1 files changed, 82 insertions, 0 deletions
| diff --git a/server.erl b/server.erl new file mode 100644 index 0000000..dbf4182 --- /dev/null +++ b/server.erl @@ -0,0 +1,82 @@ +-module(server). +-export([server/2, manager/1, broadcast/2, broadcast/3, worker/2, create_workers/2]). + +server(Port, NumWorkers) -> +    process_flag(trap_exit, true), +    {ok, ServerSock} = gen_tcp:listen(Port, [list]), +    spawn(?MODULE, create_workers, [NumWorkers, self()]), +    supervisor(ServerSock, []). + +create_workers(0, _) -> ok; +create_workers(Num, Supervisor) -> +    Supervisor ! create, +    create_workers(Num - 1, Supervisor). + +supervisor(ServerSock, Pids) -> +    receive +        create -> +            io:format("Creating new worker\n"), +            NewPid = spawn_link(?MODULE, worker, [ServerSock, Pids]), +            ping_all(Pids, NewPid), +            supervisor(ServerSock, [NewPid | Pids]); +        {'EXIT', From, Reason} -> +            io:format("~p exited due to ~p\n", [From, Reason]), +            self() ! create, +            supervisor(ServerSock, lists:delete(From, Pids)) +    end. + +ping_all([Pid|Pids], NewPid) -> +    Pid ! { ping, NewPid }, +    ping_all(Pids, NewPid); +ping_all([], _) -> ok. + +worker(ServerSock, Pids) -> +    process_flag(trap_exit, false), +    ManagerPid = self(), +    spawn_link( +        fun() -> +           process_flag(trap_exit, false), +           listener(ManagerPid, ServerSock) +        end), +    manager(Pids). + +listener(ManagerPid, ServerSock) -> +    case gen_tcp:accept(ServerSock) of +        {ok, Sock} -> +            ok = gen_tcp:controlling_process(Sock, ManagerPid), +            ManagerPid ! {ping, Sock}, +            listener(ManagerPid, ServerSock); +        Other -> +            exit(Other) +    end. + +manager(Socks) -> +    receive +        {tcp, Sock, Data} -> +            broadcast(lists:delete(Sock, Socks), Data), +            manager(Socks); +        {tcp_closed, Sock} ->  +            manager(lists:delete(Sock, Socks)); +        {ping, Sock} -> +            manager([Sock | Socks]); + +        {repeat, Data} -> +            broadcast(Socks, Data, norepeat), +            manager(Socks); +        Other -> +            exit(Other) +    end. + +broadcast([Pid|Socks], Data, norepeat) when is_pid(Pid) -> +    broadcast(Socks, Data, norepeat); +broadcast([Pid|Socks], Data, Opt) when is_pid(Pid) -> +    Pid ! {repeat, Data}, +    broadcast(Socks, Data, Opt); + +broadcast([Sock|Socks], Data, Opt)  -> +    gen_tcp:send(Sock, Data), +    broadcast(Socks, Data, Opt); +broadcast([], _, _) -> ok. + +broadcast(Socks, Data) -> +    broadcast(Socks, Data, ok). | 
