diff --git a/lib/farmbot/bootstrap/auth_task.ex b/lib/farmbot/bootstrap/auth_task.ex index 09718f16..5633ed34 100644 --- a/lib/farmbot/bootstrap/auth_task.ex +++ b/lib/farmbot/bootstrap/auth_task.ex @@ -20,6 +20,7 @@ defmodule Farmbot.Bootstrap.AuthTask do def init([]) do timer = Process.send_after(self(), :refresh, @refresh_time) + Farmbot.System.Registry.subscribe(self()) {:ok, timer, :hibernate} end @@ -29,7 +30,7 @@ defmodule Farmbot.Bootstrap.AuthTask do end end - def handle_info(:refresh, _old_timer) do + 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}") @@ -48,10 +49,21 @@ defmodule Farmbot.Bootstrap.AuthTask do {:error, err} -> msg = "Token failed to reauthorize: #{email} - #{server} #{inspect err}" Logger.error(1, msg) - refresh_timer(self(), 30_000) + # 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 diff --git a/lib/farmbot/system/registry.ex b/lib/farmbot/system/registry.ex new file mode 100644 index 00000000..9f4ea026 --- /dev/null +++ b/lib/farmbot/system/registry.ex @@ -0,0 +1,31 @@ +defmodule Farmbot.System.Registry do + @moduledoc "Farmbot System Global Registry" + @reg FarmbotRegistry + + @doc false + def start_link do + GenServer.start_link(__MODULE__, [], [name: __MODULE__]) + end + + @doc "Dispatch a global event from a namespace." + def dispatch(namespace, event) do + GenServer.call(__MODULE__, {:dispatch, namespace, event}) + end + + def subscribe(pid) do + Elixir.Registry.register(@reg, __MODULE__, pid) + end + + def init([]) do + opts = [keys: :duplicate, partitions: System.schedulers_online, name: @reg] + {:ok, reg} = Elixir.Registry.start_link(opts) + {:ok, %{reg: reg}} + end + + def handle_call({:dispatch, ns, event}, _from, state) do + Elixir.Registry.dispatch(@reg, __MODULE__, fn(entries) -> + for {pid, _} <- entries, do: send(pid, {__MODULE__, {ns, event}}) + end) + {:reply, :ok, state} + end +end diff --git a/lib/farmbot/system/supervisor.ex b/lib/farmbot/system/supervisor.ex index 364b4826..2d358f6d 100644 --- a/lib/farmbot/system/supervisor.ex +++ b/lib/farmbot/system/supervisor.ex @@ -12,6 +12,7 @@ defmodule Farmbot.System.Supervisor do def init([]) do before_init_children = [ + worker(Farmbot.System.Registry, []), worker(Farmbot.System.Init.KernelMods, [[], []]), worker(Farmbot.System.Init.FSCheckup, [[], []]), supervisor(Farmbot.System.Init.Ecto, [[], []]), diff --git a/nerves/target/bootstrap/network/manager.ex b/nerves/target/bootstrap/network/manager.ex index e19a35e9..c4f22d22 100644 --- a/nerves/target/bootstrap/network/manager.ex +++ b/nerves/target/bootstrap/network/manager.ex @@ -22,9 +22,9 @@ defmodule Farmbot.Target.Network.Manager do init(args) end SystemRegistry.register() - {:ok, _} = Registry.register(Nerves.NetworkInterface, interface, []) - {:ok, _} = Registry.register(Nerves.Udhcpc, interface, []) - {:ok, _} = Registry.register(Nerves.WpaSupplicant, interface, []) + {:ok, _} = Elixir.Registry.register(Nerves.NetworkInterface, interface, []) + {:ok, _} = Elixir.Registry.register(Nerves.Udhcpc, interface, []) + {:ok, _} = Elixir.Registry.register(Nerves.WpaSupplicant, interface, []) Network.setup(interface, opts) {:ok, %{interface: interface, ip_address: nil, connected: false, not_found_timer: nil, ntp_timer: nil, dns_timer: nil}} end @@ -105,9 +105,11 @@ defmodule Farmbot.Target.Network.Manager do # If we weren't previously connected, send a log. unless state.connected do Logger.success 3, "Farmbot was reconnected to the internet: #{inspect aliases}" + Farmbot.System.Registry.dispatch(:network, :dns_up) end {:noreply, %{state | connected: true, dns_timer: restart_dns_timer(nil, 45_000)}} {:error, err} -> + Farmbot.System.Registry.dispatch(:network, :dns_down) Logger.warn 3, "Farmbot was disconnected from the internet: #{inspect err}" {:noreply, %{state | connected: false, dns_timer: restart_dns_timer(nil, 10_000)}} end @@ -151,7 +153,6 @@ defmodule Farmbot.Target.Network.Manager do if Farmbot.System.ConfigStorage.get_config_value(:bool, "settings", "first_boot") do Process.send_after(self(), :ntp_timer, 10_000 + rand) else - Process.send_after(self(), :ntp_timer, 300000 + rand) end end diff --git a/test/farmbot/system/registry_test.exs b/test/farmbot/system/registry_test.exs new file mode 100644 index 00000000..0c520fb3 --- /dev/null +++ b/test/farmbot/system/registry_test.exs @@ -0,0 +1,10 @@ +defmodule Farmbot.System.RegistryTest do + use ExUnit.Case + alias Farmbot.System.Registry + + test "subscribes and dispatches global events" do + Registry.subscribe(self()) + Registry.dispatch(:hello, :world) + assert_receive {Registry, {:hello, :world}} + end +end