Skip to content

Commit

Permalink
Implement mechanism to refresh Firestore access tokens before expiry
Browse files Browse the repository at this point in the history
  • Loading branch information
MajdSehwail committed Aug 6, 2023
1 parent a2c66b9 commit 00e9027
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 8 deletions.
53 changes: 46 additions & 7 deletions lib/firestore.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,32 @@ defmodule Firestore do
This is the main entry point for the Firestore application.
"""

defmodule State do
defstruct [
:config,
:client
]

@type t :: %__MODULE__{
config: map(),
client: Connection.t()
}
end

use GenServer

def init(%{otp_app: app} = config) do
credentials = Enum.into(config, %{}, fn {k, v} -> {to_string(k), v} end)
alias Firestore.Connection
alias Goth.Token

with {:ok, %{token: token}} <- Goth.Token.fetch(source: {:service_account, credentials}) do
client = Firestore.Connection.init(token, config)
@ets_table :firestore_table
@refresh_token_interval_ms 1 * 60 * 1000

:ets.new(:firestore_conn_table, [:set, :public, :named_table])
:ets.insert(:firestore_conn_table, {:"#{app}_firestore_client", client})
{:ok, client}
@impl true
def init(config) do
:ets.new(@ets_table, [:set, :public, :named_table])

with {:ok, client} <- init_client(config) do
{:ok, %State{config: config, client: client}}
end
end

Expand All @@ -24,4 +39,28 @@ defmodule Firestore do
def child_spec(opts) do
%{id: __MODULE__, start: {__MODULE__, :start_link, [opts]}}
end

@impl true
def handle_info(:refresh_token, %State{config: config} = state) do
case init_client(config) do
{:ok, client} ->
{:noreply, %State{state | client: client}}

{:error, reason} ->
{:stop, reason}
end
end

defp init_client(%{otp_app: app} = config) do
credentials = Enum.into(config, %{}, fn {k, v} -> {to_string(k), v} end)

with {:ok, %{token: token}} <- Token.fetch(source: {:service_account, credentials}) do
client = Connection.init(token, config)

:ets.insert(@ets_table, {:"#{app}_firestore_client", client})
Process.send_after(self(), :refresh_token, @refresh_token_interval_ms)

{:ok, client}
end
end
end
2 changes: 1 addition & 1 deletion lib/firestore/repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ defmodule Firestore.Repo do
end

defp get_client() do
case :ets.lookup(:firestore_conn_table, :"#{@otp_app}_firestore_client") do
case :ets.lookup(:firestore_table, :"#{@otp_app}_firestore_client") do
[{_, %Tesla.Client{} = client}] ->
{:ok, client}

Expand Down

0 comments on commit 00e9027

Please sign in to comment.