lib/a2s/udp.ex

defmodule A2S.UDP do
  @moduledoc """
  GenServer wrapper over `:gen_udp`, responsible for sending packets to game-servers and routing received packets to the appropriate `A2S.Statem` process.
  """

  use GenServer

  ## API

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, [name: __MODULE__])
  end

  ## Callbacks

  @impl true
  def init([port: port]) do
    case :gen_udp.open(port, [:binary, active: true]) do
      {:error, reason} -> {:stop, reason}
      {:ok, socket} -> {:ok, socket}
    end
  end

  @doc """
  Forward received packets to the appropriate `A2S.Statem`.
  """
  @impl true
  def handle_info({:udp, _socket, ip, port, packet}, socket) do
    GenServer.cast(via_registry({ip, port}), packet)
    {:noreply, socket}
  end

  @doc """
  Send the given `msg` packet to the game server.
  """
  @impl true
  def handle_call({address, packet}, _from, socket) do
    with :ok <- :gen_udp.send(socket, address, packet) do
      {:reply, :ok, socket}
    else
      err -> {:reply, err, socket}
    end
  end

  ## Functions

  defp via_registry(name), do: {:via, Registry, {:a2s_registry, name}}
end