farmbot_os/lib/farmbot/bootstrap/auth_task.ex

105 lines
3.1 KiB
Elixir

defmodule Farmbot.Bootstrap.AuthTask do
@moduledoc "Background worker that refreshes a token every 30 minutes."
use GenServer
use Farmbot.Logger
alias Farmbot.System.ConfigStorage
import ConfigStorage, only: [update_config_value: 4, get_config_value: 3]
# 30 minutes.
@refresh_time 1.8e+6 |> round()
# @refresh_time 5_000
@doc false
def start_link() do
GenServer.start_link(__MODULE__, [], [name: __MODULE__])
end
def force_refresh do
GenServer.call(__MODULE__, :force_refresh)
end
def init([]) do
timer = Process.send_after(self(), :refresh, @refresh_time)
Farmbot.System.Registry.subscribe(self())
{:ok, timer, :hibernate}
end
def terminate(reason, _state) do
unless reason == {:shutdown, :normal} do
Logger.error 1, "Token Refresh failed: #{inspect reason}"
end
end
defp do_refresh do
auth_task = Application.get_env(:farmbot, :behaviour)[:authorization]
{email, pass, server} = {fetch_email(), fetch_pass(), fetch_server()}
# Logger.busy(3, "refreshing token: #{email} - #{server}")
Farmbot.System.GPIO.Leds.led_status_err()
case auth_task.authorize(email, pass, server) do
{:ok, token} ->
# Logger.success(3, "Successful authorization: #{email} - #{server}")
update_config_value(:bool, "settings", "first_boot", false)
update_config_value(:string, "authorization", "token", token)
Farmbot.System.GPIO.Leds.led_status_ok()
if get_config_value(:bool, "settings", "auto_sync") do
Farmbot.Repo.flip()
end
Farmbot.System.Registry.dispatch :authorization, :new_token
restart_transports()
refresh_timer(self())
{:error, err} ->
msg = "Token failed to reauthorize: #{email} - #{server} #{inspect err}"
Logger.error(1, msg)
# If refresh failed, try again more often
refresh_timer(self(), 15_000)
end
end
def handle_info(:refresh, _old_timer) do
do_refresh()
end
def handle_info({Farmbot.System.Registry, {:network, :dns_up}}, _old_timer) do
do_refresh()
end
def handle_info({Farmbot.System.Registry, _}, timer), do: {:noreply, timer}
def handle_call(:force_refresh, _, old_timer) do
Logger.info 1, "Forcing a token refresh."
if Process.read_timer(old_timer) do
Process.cancel_timer(old_timer)
end
send self(), :refresh
{:reply, :ok, nil}
end
defp restart_transports do
transports = Application.get_env(:farmbot, :transport)
for t <- transports do
t.stop(:token_refresh)
end
:ok
end
defp refresh_timer(pid, ms \\ @refresh_time) do
timer = Process.send_after(pid, :refresh, ms)
{:noreply, timer, :hibernate}
end
defp fetch_email do
email = get_config_value(:string, "authorization", "email")
email || raise "No email provided for token refresh."
end
defp fetch_pass do
pass = get_config_value(:string, "authorization", "password")
pass || raise "No password provided for token refresh."
end
defp fetch_server do
server = get_config_value(:string, "authorization", "server")
server || raise "No server provided for token refresh."
end
end