Current section

Files

Jump to
mob lib mob plugins lifecycle.ex
Raw

lib/mob/plugins/lifecycle.ex

defmodule Mob.Plugins.Lifecycle do
@moduledoc """
Dispatches OS foreground/background transitions to the tier-4 plugins'
`lifecycle.on_resume` / `lifecycle.on_background` hooks.
Subscribes to `Mob.Device`'s `:app` events and, on `:did_become_active` /
`:did_enter_background`, invokes each plugin's corresponding MFA. A plugin
that didn't declare a hook is simply skipped. Supervised by
`Mob.Plugins.Supervisor`.
"""
use GenServer
require Logger
@spec start_link(term()) :: GenServer.on_start()
def start_link(_arg), do: GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
@impl GenServer
def init(:ok) do
Mob.Device.subscribe(:app)
{:ok, Mob.Plugins.lifecycle()}
end
@impl GenServer
def handle_info({:mob_device, :did_become_active}, lifecycles) do
run_hooks(lifecycles, :on_resume)
{:noreply, lifecycles}
end
def handle_info({:mob_device, :did_enter_background}, lifecycles) do
run_hooks(lifecycles, :on_background)
{:noreply, lifecycles}
end
def handle_info(_msg, lifecycles), do: {:noreply, lifecycles}
defp run_hooks(lifecycles, key) do
for lc <- lifecycles, mfa = lc[key], not is_nil(mfa) do
invoke(mfa, lc[:plugin], key)
end
end
# A misbehaving hook must not take down the dispatcher (and with it every
# other plugin's hooks) — log and continue.
defp invoke({m, f, a}, plugin, key) do
apply(m, f, a)
rescue
e ->
Logger.error(
"[mob_plugins] #{inspect(plugin)} #{key} crashed: " <>
Exception.format(:error, e, __STACKTRACE__)
)
end
end