geo-therminator/lib/geo_therminator/pump_api/auth/server.ex
2021-11-07 11:01:39 +02:00

106 lines
2.7 KiB
Elixir

defmodule GeoTherminator.PumpAPI.Auth.Server do
use GenServer
import GeoTherminator.TypedStruct
alias GeoTherminator.PumpAPI.Auth
require Logger
@token_check_timer 10_000
@token_check_diff 5 * 60
defmodule Options do
deftypedstruct(%{
server_name: GenServer.name(),
username: String.t(),
password: String.t()
})
end
defmodule State do
deftypedstruct(%{
username: String.t(),
password: String.t(),
authed_user: {Auth.User.t() | nil, nil},
installations_fetched: {boolean(), false},
installations: {[Auth.InstallationInfo.t()], []}
})
end
@spec start_link(Options.t()) :: GenServer.on_start()
def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: opts.server_name)
end
@impl true
def init(%Options{} = opts) do
{:ok, %State{username: opts.username, password: opts.password}, {:continue, :init}}
end
@impl true
def handle_continue(:init, state) do
user = Auth.API.auth(state.username, state.password)
installations = Auth.API.installations_info(user)
schedule_token_check()
state = %State{
state
| authed_user: user,
installations: installations,
installations_fetched: true
}
{:noreply, state}
end
@impl true
def handle_call(msg, from, state)
def handle_call(:get_auth, _from, state) do
{:reply, state.authed_user, state}
end
def handle_call(:get_installations, _from, state) do
{:reply, state.installations, state}
end
def handle_call({:get_installation, id}, _from, state) do
{:reply, Enum.find(state.installations, &(&1.id == id)), state}
end
@impl true
def handle_info(msg, state)
def handle_info(:token_check, state) do
now = DateTime.utc_now()
diff = DateTime.diff(state.authed_user.token.token_valid_to, now)
schedule_token_check()
if diff < @token_check_diff do
Logger.debug("Renewing auth token since #{diff} < #{@token_check_diff}")
user = Auth.API.auth(state.username, state.password)
{:noreply, %State{state | authed_user: user}}
else
{:noreply, state}
end
end
@spec get_auth(GenServer.name()) :: Auth.User.t()
def get_auth(server) do
GenServer.call(server, :get_auth)
end
@spec get_installations(GenServer.name()) :: Auth.InstallationInfo.t()
def get_installations(server) do
GenServer.call(server, :get_installations)
end
@spec get_installation(GenServer.name(), integer()) :: Auth.InstallationInfo.t() | nil
def get_installation(server, id) do
GenServer.call(server, {:get_installation, id})
end
defp schedule_token_check() do
Process.send_after(self(), :token_check, @token_check_timer)
end
end