Initial
This commit is contained in:
		
							
								
								
									
										65
									
								
								lib/server.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								lib/server.ex
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
defmodule Broadcast.Server do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
    Implements the server. The server spawns a new process
 | 
			
		||||
    for every client - the processes usually don't really talk to
 | 
			
		||||
    each other, so this is trivial.
 | 
			
		||||
  """
 | 
			
		||||
  use GenServer
 | 
			
		||||
  use Agent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def init(port) do
 | 
			
		||||
    {:ok, sock} = :gen_tcp.listen(port, [:binary, packet: :line, active: false, reuseaddr: true])
 | 
			
		||||
    spawn_link(fn -> accept_loop(sock) end)
 | 
			
		||||
    {:ok, {sock, %{}}}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp accept_loop(sock) do
 | 
			
		||||
    case :gen_tcp.accept(sock) do
 | 
			
		||||
      {:ok, client_socket} ->
 | 
			
		||||
        {:ok, pid} = Broadcast.ClientHandler.start(client_socket)
 | 
			
		||||
        GenServer.cast(__MODULE__, {:new_client, pid, client_socket})
 | 
			
		||||
        accept_loop(sock)
 | 
			
		||||
      {:error, _} ->
 | 
			
		||||
        accept_loop(sock)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_cast({:new_client, pid, client_sock}, {sock, clients}) do
 | 
			
		||||
    {:noreply, {sock, clients |> Map.put(pid, client_sock)}}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_cast({:remove, client}, {sock, clients}) do
 | 
			
		||||
    new_clients = Map.delete(clients, client)
 | 
			
		||||
    {:noreply, {sock, new_clients}}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_cast({:broadcast, msg, sender}, {sock, clients}) do
 | 
			
		||||
    clients |> Enum.map(fn {p, s} ->
 | 
			
		||||
      if sender != p do
 | 
			
		||||
        :gen_tcp.send(s, msg)
 | 
			
		||||
      end
 | 
			
		||||
    end)
 | 
			
		||||
    {:noreply, {sock, clients}}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Print out the memory usage for the client processes specifically
 | 
			
		||||
 | 
			
		||||
  # From this point onwards is the actual API for this module,
 | 
			
		||||
  # that should be called by ClientHandlers and main
 | 
			
		||||
 | 
			
		||||
  @spec start(integer()) :: pid()
 | 
			
		||||
  def start(port) when is_integer(port) do
 | 
			
		||||
    GenServer.start_link(__MODULE__, port, name: __MODULE__)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def broadcast(msg) do
 | 
			
		||||
    GenServer.cast(__MODULE__, {:broadcast, msg, self()})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def remove_client() do
 | 
			
		||||
    GenServer.cast(__MODULE__, {:remove, self()})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user