File size: 3,145 Bytes
2e92879
89df778
 
c0e2bf5
 
89df778
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40d9f07
89df778
 
 
 
 
 
 
 
c0e2bf5
2e92879
40d9f07
c0e2bf5
 
89df778
 
 
 
 
 
 
 
c0e2bf5
89df778
40d9f07
 
 
 
89df778
c0e2bf5
89df778
 
 
 
b2ff4b5
89df778
 
 
40d9f07
 
 
 
 
 
 
 
bb41a4c
 
 
 
 
 
 
40d9f07
 
 
 
 
 
89df778
 
 
 
 
 
 
c0e2bf5
89df778
 
 
c0e2bf5
 
 
40d9f07
 
 
bb41a4c
 
 
 
 
 
 
 
 
 
 
 
 
2e92879
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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