diff options
author | kartofen <mladenovnasko0@gmail.com> | 2024-02-05 01:28:07 +0200 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2024-02-05 01:28:07 +0200 |
commit | 3037bf26dc938f56c5ef63ddf04027a1f3f629c6 (patch) | |
tree | 8f6cc8a47330c14beb4fff6d7344fa6fbd854b21 |
init
-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). |