defmodule SNet.Manager do use GenServer def start_link(my_port) do GenServer.start_link(__MODULE__, my_port, name: __MODULE__) end def init(my_port) do state = %{ peers: %{}, my_port: my_port } {:ok, state} end def handle_cast({:peer_up, pk, pid, addr, ip}, state) do new_peers = Map.put(state.peers, pk, {pid, addr, ip}) new_state = %{ state | peers: new_peers } {:noreply, new_state} end def handle_cast({:peer_down, pk, addr, ip}, state) do new_peers = Map.put(state.peers, pk, {nil, addr, ip}) new_state = %{ state | peers: new_peers } {:noreply, new_state} end def handle_cast({:add_peer, ip, port}, state) do add_peer(ip, port, state.my_port) {:noreply, state} end def handle_cast({:try_connect, pk_list}, state) do for pk <- pk_list do case state.peers[pk] do {nil, ip, port} -> add_peer(ip, port) _ -> nil end end {:noreply, state} end def handle_call(:get_all, _from, state) do pid_list = (for {_, {pid, _, _}} <- state.peers, pid != nil, do: pid) {:reply, pid_list, state} end def handle_call({:get_connections, pk_list}, _from, state) do pid_list = (for pk <- pk_list, Map.has_key?(state.peers, pk), do: state.peers[pk]) |> Enum.map(fn {pid, _, _} -> pid end) |> Enum.filter(&(&1 != nil)) {:ok, pid_list, state} end def add_peer(ip, port) do GenServer.cast(__MODULE__, {:add_peer, ip, port}) end def add_peer(ip, port, my_port) do {:ok, client} = :gen_tcp.connect(ip, port, [:binary, packet: 2, active: false]) {:ok, pid} = DynamicSupervisor.start_child(Shard.DynamicSupervisor, {SNet.TCPConn, %{socket: client, my_port: my_port}}) :ok = :gen_tcp.controlling_process(client, pid) pid end end