Spaces:
Sleeping
Sleeping
| 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 | |