summaryrefslogblamecommitdiff
path: root/lib/irc/plugin_supervisor.ex
blob: 5f93f1760f447620274be6a3f40b82fa53d23168 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12




                         
                  





                                                                    
                                       
                                                                                                                            








                                                                                  











































































                                                                                      
defmodule IRC.Plugin do
  require Logger

  defmodule Supervisor do
    use DynamicSupervisor
    require Logger

    def start_link() do
      DynamicSupervisor.start_link(__MODULE__, [], name: __MODULE__)
    end

    def start_child(module, opts \\ []) do
      Logger.info("Starting #{module}")
      spec = %{id: {IRC.Plugin,module}, start: {IRC.Plugin, :start_link, [module, opts]}, name: module, restart: :transient}
      case DynamicSupervisor.start_child(__MODULE__, spec) do
        {:ok, _} = res -> res
        :ignore ->
          Logger.info("Ignored #{module}")
          :ignore
        {:error,_} = res ->
          Logger.error("Could not start #{module}: #{inspect(res, pretty: true)}")
          res
      end
    end

    @impl true
    def init(_init_arg) do
      DynamicSupervisor.init(
        strategy: :one_for_one,
        max_restarts: 10,
        max_seconds: 1
      )
    end
  end

  def dets(), do: to_charlist(LSG.data_path("/plugins.dets"))

  def setup() do
    :dets.open_file(dets(), [])
  end

  def enabled() do
    :dets.foldl(fn
      {name, true, _}, acc -> [name | acc]
      _, acc -> acc
    end, [], dets())
  end

  def start_all() do
    for mod <- enabled(), do: {mod, IRC.Plugin.Supervisor.start_child(mod)}
  end

  def declare(module) do
    case get(module) do
      :disabled -> :dets.insert(dets(), {module, true, nil})
      _ -> nil
    end
  end

  def start(module, opts \\ []) do
    IRC.Plugin.Supervisor.start_child(module)
  end

  @doc "Enables a plugin"
  def enable(name), do: switch(name, true)

  @doc "Disables a plugin"
  def disable(name), do: switch(name, false)

  @doc "Enables or disables a plugin"
  def switch(name, value) when is_boolean(value) do
    last = case get(name) do
      {:ok, last} -> last
      _ -> nil
    end
    :dets.insert(dets(), {name, value, last})
  end

  @spec get(module()) :: {:ok, last_start :: nil | non_neg_integer()} | :disabled
  def get(name) do
    case :dets.lookup(dets(), name) do
      [{name, enabled, last_start}] -> {:ok, enabled, last_start}
      _ -> :disabled
    end
  end

  def start_link(module, options \\ []) do
    with {:disabled, {_, true, last}} <- {:disabled, get(module)},
          {:throttled, false} <- {:throttled, false}
    do
      module.start_link()
    else
      {error, _} ->
        Logger.info("Plugin: #{to_string(module)} ignored start: #{to_string(error)}")
        :ignore
    end
  end

end