Finish plugin and routing overhaul, there's a new model in town:

* Plugins all derive from Omnibot.Plugin. There still is a base plugin,
  in case we want to have another plugin backend instead of a GenServer
* All plugins are monitored by a unique Plugin.Supervisor, which is in
  turn started by the PluginSupervisor (yes this is confusing, yes it
  needs to be renamed)
* Any other auxiliary child processes may be started through the
  Plugin.children/1 function.
* By default, plugins have a CfgState process which is an Agent that
  keeps track of the plugin's configuration and state
* Plugin API is now called through the GenServer backend for better
  synchronicity.
* Very few changes to the front-facing Plugin API, which is nice

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-07-14 15:05:00 -07:00
parent 9679c46e15
commit 522c62a55c
6 changed files with 67 additions and 43 deletions

View File

@@ -19,6 +19,11 @@ defmodule Omnibot.Plugin.Base do
@impl true
def on_init(_cfg), do: nil
@impl true
def on_msg(irc, msg) do
route_msg(irc, msg)
end
@impl true
def default_config(), do: @default_config
@@ -33,11 +38,6 @@ defmodule Omnibot.Plugin.Base do
@behaviour Plugin.Base
@impl Plugin.Base
def on_msg(irc, msg) do
route_msg(irc, msg)
end
defp route_msg(irc, %Irc.Msg {prefix: nil}), do: nil
defp route_msg(irc, msg) do

View File

@@ -14,21 +14,24 @@ defmodule Omnibot.Plugin do
def state(pid), do: Agent.get(pid, fn {_, state} -> state end)
def update_state(pid, fun, timeout \\ 5000),
do: Agent.update(pid, &{&1, apply(fun, [&1])}, timeout)
def update_state(pid, fun, timeout \\ 5000) do
Agent.update(pid, fn {cfg, state} -> {cfg, apply(fun, [state])} end, timeout)
#Agent.update(pid, &{&1, apply(fun, [&1])}, timeout)
end
end
defmacro __using__(opts) do
opts = opts ++ @default_opts
quote do
use Supervisor
quote generated: true do
use GenServer
use Omnibot.Plugin.Base
## Client API
def start_link(opts) do
Supervisor.start_link(__MODULE__, {opts[:cfg], opts[:state]}, opts)
{cfg, opts} = Keyword.pop(opts, :cfg)
GenServer.start_link(__MODULE__, cfg, opts)
end
def cfg() do
@@ -48,30 +51,37 @@ defmodule Omnibot.Plugin do
GenServer.cast(__MODULE__, {:handle_msg, irc, msg})
end
@impl Omnibot.Plugin
def children(_cfg, _state), do: []
## Server callbacks
@impl Supervisor
def init({cfg, state}) do
base_children = [
{Omnibot.Plugin.CfgState, cfg: cfg, state: state, name: __MODULE__.CfgState},
]
children =
(if unquote(opts[:include_base]), do: base_children, else: []) ++ children(cfg, state)
Supervisor.init(children, unquote(opts[:opts]))
@impl GenServer
def init(_cfg) do
{:ok, nil}
end
@impl GenServer
def handle_cast({:handle_msg, irc, msg}, state) do
on_msg(irc, msg)
{:noreply, state}
end
defp base_children(cfg, state) when unquote(opts[:include_base]) do
[
{Omnibot.Plugin.CfgState, cfg: cfg, state: state, name: __MODULE__.CfgState},
{__MODULE__, name: __MODULE__},
]
end
defp base_children(_cfg, _state), do: []
@impl Omnibot.Plugin
def children(cfg), do: []
def plugin_children(cfg, state), do: base_children(cfg, state) ++ children(cfg)
@behaviour Omnibot.Plugin
defoverridable Omnibot.Plugin
end
end
@callback children(cfg :: [atom: any], state :: any) :: [atom | {atom, [atom: any]} | {atom, any, [atom: any]}]
@callback children(cfg :: [atom: any]) :: [atom | {atom, [atom: any]} | {atom, any, [atom: any]}]
end

28
lib/plugin/supervisor.ex Normal file
View File

@@ -0,0 +1,28 @@
defmodule Omnibot.Plugin.Supervisor do
use Supervisor
def start_link(opts) do
{plugin, opts} = Keyword.pop(opts, :plugin)
{cfg, opts} = Keyword.pop(opts, :cfg)
start_link(plugin, cfg, opts)
end
def start_link(plugin, cfg, opts) when is_atom(plugin) do
Supervisor.start_link(__MODULE__, {plugin, cfg}, opts)
end
def child_spec(arg) do
id = Module.concat(arg[:plugin], Plugin.Supervisor)
%{
id: id,
start: {__MODULE__, :start_link, [arg]},
}
end
@impl true
def init({plugin, cfg}) when is_atom(plugin) do
state = plugin.on_init(cfg)
children = IO.inspect(plugin.plugin_children(cfg, state))
Supervisor.init(children, strategy: :one_for_one)
end
end