defmodule FirebaseAuth.PublicKeyServer do
use GenServer
require Logger
@interval 60 * 60
@impl true
def init(:ok) do
updated_at = 0
keys = %{}
{:ok, %{updated_at: updated_at, keys: keys}}
end
@impl true
def handle_call({:get_key, kid}, _from, %{updated_at: updated_at, keys: keys} = state) do
if now() < @interval + updated_at do
key = Map.fetch(keys, kid)
{:reply, key, state}
else
Logger.info(fn -> "Refetching keys..." end)
with {:ok, new_keys} <- FirebaseAuth.Client.get() do
key = Map.fetch(new_keys, kid)
new_state = %{updated_at: now(), keys: new_keys}
{:reply, key, new_state}
else
{:error, error} ->
Logger.warn(fn -> "Fetching key ids error: #{error}" end)
key = Map.fetch(keys, kid)
{:reply, key, state}
end
end
end
@impl true
def handle_info(_, state) do
{:noreply, state}
end
# Client API
def start_link(_opts) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
@spec get_key(binary()) :: {:ok, binary()} | :error
def get_key(kid) do
GenServer.call(__MODULE__, {:get_key, kid})
end
defp now do
:os.system_time(:second)
end
end