defmodule Tarakan.GitSSH.AuthSweeper do
  @moduledoc """
  Periodically removes stale entries from the SSH auth handoff ETS table.

  `Tarakan.GitSSH.KeyStore.is_auth_key/3` inserts `{pid, account_id,
  ssh_key_id}` keyed by the connection handler pid as soon as a public key
  is recognized. The channel normally takes the entry out, but when the
  subsequent signature verification fails the connection dies first and the
  entry would linger forever. Deleting entries whose pid is no longer alive
  keeps the table bounded.
  """

  use GenServer

  alias Tarakan.GitSSH.Server

  @sweep_interval_ms :timer.minutes(1)

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: Keyword.get(opts, :name, __MODULE__))
  end

  @impl true
  def init(_opts) do
    schedule_sweep()
    {:ok, nil}
  end

  @impl true
  def handle_info(:sweep, state) do
    sweep()
    schedule_sweep()
    {:noreply, state}
  end

  @doc false
  def sweep do
    table = Server.auth_table()

    if :ets.whereis(table) != :undefined do
      table
      |> :ets.tab2list()
      |> Enum.each(fn {pid, _account_id, _ssh_key_id} = entry ->
        unless Process.alive?(pid), do: :ets.delete_object(table, entry)
      end)
    end

    :ok
  end

  defp schedule_sweep do
    Process.send_after(self(), :sweep, @sweep_interval_ms)
  end
end
