summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2024-02-05 01:28:07 +0200
committerkartofen <mladenovnasko0@gmail.com>2024-02-05 01:28:07 +0200
commit3037bf26dc938f56c5ef63ddf04027a1f3f629c6 (patch)
tree8f6cc8a47330c14beb4fff6d7344fa6fbd854b21
init
-rw-r--r--server.erl82
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).