kiola / lib /srh /auth /token_resolver.ex
Scott Hiett
Better error handling for failure to connect to Redis server
bb41a4c
defmodule Srh.Auth.TokenResolver do
use GenServer
@file_path Application.fetch_env!(:srh, :file_path)
@ets_table_name :srh_token_resolver
def start_link() do
GenServer.start_link(__MODULE__, {}, [])
end
def child_spec(_opts) do
%{
id: :token_resolver,
start: {__MODULE__, :start_link, []},
type: :supervisor
}
end
def init(_arg) do
IO.puts("Token resolver started")
# Create the ETS table
table = :ets.new(@ets_table_name, [:named_table, read_concurrency: true])
# Populate the ETS table with data from storage
do_init_load(get_token_loader_mode())
{
:ok,
%{
table: table
}
}
end
def resolve(token) do
do_resolve(get_token_loader_mode(), token)
end
# Server methods
def handle_call(_msg, _from, state) do
{:reply, :ok, state}
end
def handle_cast(_msg, state) do
{:noreply, state}
end
# Internal server
defp get_token_loader_mode() do
System.get_env("SRH_MODE", "file")
end
defp do_init_load("file") do
config_file_data = Jason.decode!(File.read!(@file_path))
IO.puts("Loaded config file from disk. #{map_size(config_file_data)} entries.")
# Load this into ETS
Enum.each(
config_file_data,
&:ets.insert(@ets_table_name, &1)
)
end
defp do_init_load("env") do
srh_token = System.get_env("SRH_TOKEN")
srh_connection_string = System.get_env("SRH_CONNECTION_STRING")
# Returns an error if fails, first tuple value is the number
{srh_max_connections, ""} = Integer.parse(System.get_env("SRH_MAX_CONNECTIONS", "3"))
# Create a config-file-like structure that the ETS layout expects, with just one entry
config_file_data =
Map.put(%{}, srh_token, %{
# Jason.parse! expects these keys to be strings, not atoms, so we need to replicate that setup
"srh_id" => "env_config_connection",
"connection_string" => srh_connection_string,
"max_connections" => srh_max_connections
})
IO.puts("Loaded config from env. #{map_size(config_file_data)} entries.")
# Load this into ETS
Enum.each(config_file_data, &:ets.insert(@ets_table_name, &1))
end
defp do_init_load(_), do: :ok
# Internal, but client side, methods. These are client side to prevent GenServer lockup
defp do_resolve("file", token) do
# if @hard_file_reload do
# do_init_load("file")
# end
case :ets.lookup(@ets_table_name, token) do
[{^token, connection_info}] -> {:ok, connection_info}
[] -> {:error, "Invalid token"}
end
end
# The env strategy uses the same ETS table as the file strategy, so we can fall back on that
defp do_resolve("env", token), do: do_resolve("file", token)
# defp do_resolve("redis", _token) do
# {
# :ok,
# # This is done to replicate what will eventually be API endpoints, so they keys are not atoms
# Jason.decode!(
# Jason.encode!(%{
# srh_id: "1000",
# connection_string: "redis://localhost:6379",
# max_connections: 10
# })
# )
# }
# end
end