Add lib/plugin that was removed in the last commit, whoops
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
40
lib/plugin/agent.ex
Normal file
40
lib/plugin/agent.ex
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
defmodule Omnibot.Plugin.Agent do
|
||||||
|
defmacro __using__([]) do
|
||||||
|
quote do
|
||||||
|
alias Omnibot.Plugin
|
||||||
|
use Agent
|
||||||
|
|
||||||
|
def start_link(opts) do
|
||||||
|
cfg = opts[:cfg]
|
||||||
|
state = opts[:state] || on_init(cfg)
|
||||||
|
Plugin.Agent.start_link(cfg, state, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cfg, do: Plugin.Agent.cfg(__MODULE__)
|
||||||
|
def state, do: Plugin.Agent.state(__MODULE__)
|
||||||
|
|
||||||
|
def update_state(update, timeout \\ 5000),
|
||||||
|
do: Plugin.Agent.update_state(__MODULE__, update, timeout)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_link(cfg, state, opts) do
|
||||||
|
Agent.start_link(fn -> {cfg, state} end, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cfg(agent) do
|
||||||
|
Agent.get(agent, fn {cfg, _} -> cfg end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def state(agent) do
|
||||||
|
Agent.get(agent, fn {_, state} -> state end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_state(agent, update, timeout \\ 5000) do
|
||||||
|
Agent.update(
|
||||||
|
agent,
|
||||||
|
fn {cfg, state} -> {cfg, apply(update, [state])} end,
|
||||||
|
timeout
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
129
lib/plugin/base.ex
Normal file
129
lib/plugin/base.ex
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
defmodule Omnibot.Plugin.Base do
|
||||||
|
defmodule Hooks do
|
||||||
|
defmacro __before_compile__(_env) do
|
||||||
|
quote generated: true do
|
||||||
|
@impl true
|
||||||
|
def on_channel_msg(_irc, _channel, _nick, _line), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_channel_msg(_irc, _channel, _nick, _cmd, _params), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_join(_irc, _channel, _nick), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_part(_irc, _channel, _nick), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_kick(_irc, _channel, _nick, _target), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_init(_cfg), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def default_config(), do: @default_config
|
||||||
|
|
||||||
|
def commands(), do: MapSet.to_list(@commands)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defmacro __using__([]) do
|
||||||
|
quote do
|
||||||
|
alias Omnibot.{Irc, Plugin}
|
||||||
|
import Omnibot.Plugin.Base
|
||||||
|
|
||||||
|
@behaviour Plugin.Base
|
||||||
|
|
||||||
|
@impl Plugin.Base
|
||||||
|
def on_msg(irc, msg) do
|
||||||
|
# TODO - instead of using a router for modules, consider using a PubSub with a Registry:
|
||||||
|
# https://hexdocs.pm/elixir/master/Registry.html#module-using-as-a-pubsub
|
||||||
|
route_msg(irc, msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp route_msg(irc, msg) do
|
||||||
|
nick = msg.prefix.nick
|
||||||
|
case String.upcase(msg.command) do
|
||||||
|
"PRIVMSG" ->
|
||||||
|
[channel | params] = msg.params
|
||||||
|
line = Enum.join(params, " ")
|
||||||
|
|
||||||
|
case String.split(line, " ") do
|
||||||
|
[cmd | params] -> if Enum.member?(commands(), cmd),
|
||||||
|
do: on_channel_msg(irc, channel, nick, cmd, params),
|
||||||
|
else: on_channel_msg(irc, channel, nick, line)
|
||||||
|
_ -> on_channel_msg(irc, channel, nick, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
"JOIN" ->
|
||||||
|
[channel | _] = msg.params
|
||||||
|
on_join(irc, channel, nick)
|
||||||
|
|
||||||
|
"PART" ->
|
||||||
|
[channel | _] = msg.params
|
||||||
|
on_part(irc, channel, nick)
|
||||||
|
|
||||||
|
"KICK" ->
|
||||||
|
[channel, target | _] = msg.params
|
||||||
|
on_kick(irc, channel, nick, target)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defoverridable Plugin.Base
|
||||||
|
|
||||||
|
@commands MapSet.new()
|
||||||
|
@default_config []
|
||||||
|
@before_compile Omnibot.Plugin.Base.Hooks
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@callback on_msg(irc :: pid(), msg :: %Omnibot.Irc.Msg{}) :: any
|
||||||
|
@callback on_channel_msg(irc :: pid(), channel :: String.t(), nick :: String.t(), line :: String.t()) :: any
|
||||||
|
@callback on_channel_msg(
|
||||||
|
irc :: pid(),
|
||||||
|
channel :: String.t(),
|
||||||
|
nick :: String.t(),
|
||||||
|
cmd :: String.t(),
|
||||||
|
params :: [String.t()]
|
||||||
|
) :: any
|
||||||
|
@callback on_join(irc :: pid(), channel :: String.t(), nick :: String.t()) :: any
|
||||||
|
@callback on_part(irc :: pid(), channel :: String.t(), nick :: String.t()) :: any
|
||||||
|
@callback on_kick(irc :: pid(), channel :: String.t(), nick :: String.t(), target :: String.t()) :: any
|
||||||
|
@callback on_init(cfg :: any) :: any
|
||||||
|
@callback default_config() :: any
|
||||||
|
|
||||||
|
defmacro command(cmd, opts) do
|
||||||
|
quote generated: true do
|
||||||
|
@commands MapSet.put(@commands, unquote(cmd))
|
||||||
|
@impl Omnibot.Plugin.Base
|
||||||
|
def on_channel_msg(var!(irc), var!(channel), var!(nick), unquote(cmd), var!(params)) do
|
||||||
|
unquote(opts[:do])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defmacro command(cmd, params, opts) do
|
||||||
|
params =
|
||||||
|
Enum.map(
|
||||||
|
params,
|
||||||
|
fn param ->
|
||||||
|
case param do
|
||||||
|
{_, _, _} -> quote(do: var!(unquote(param)))
|
||||||
|
lit -> Macro.escape(lit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
quote generated: true do
|
||||||
|
@commands MapSet.put(@commands, unquote(cmd))
|
||||||
|
@impl Omnibot.Plugin.Base
|
||||||
|
def on_channel_msg(var!(irc), var!(channel), var!(nick), unquote(cmd), unquote(params)) do
|
||||||
|
unquote(opts[:do])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
50
lib/plugin/gen_server.ex
Normal file
50
lib/plugin/gen_server.ex
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
defmodule Omnibot.Plugin.GenServer do
|
||||||
|
defmacro __using__([]) do
|
||||||
|
quote do
|
||||||
|
alias Omnibot.Plugin
|
||||||
|
use GenServer
|
||||||
|
|
||||||
|
def start_link(opts) do
|
||||||
|
cfg = opts[:cfg]
|
||||||
|
state = opts[:state]
|
||||||
|
GenServer.start_link(__MODULE__, {cfg, state}, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cfg() do
|
||||||
|
GenServer.call(__MODULE__, :cfg)
|
||||||
|
end
|
||||||
|
|
||||||
|
def state() do
|
||||||
|
GenServer.call(__MODULE__, :state)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_state(update) do
|
||||||
|
GenServer.cast(__MODULE__, {:state, update})
|
||||||
|
end
|
||||||
|
|
||||||
|
## Server callbacks
|
||||||
|
|
||||||
|
@impl GenServer
|
||||||
|
def init({cfg, state}) do
|
||||||
|
state = state || on_init(cfg)
|
||||||
|
{:ok, {cfg, state}}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl GenServer
|
||||||
|
def handle_call(:cfg, _from, {cfg, state}) do
|
||||||
|
{:reply, cfg, {cfg, state}}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl GenServer
|
||||||
|
def handle_call(:state, _from, {cfg, state}) do
|
||||||
|
{:reply, state, {cfg, state}}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl GenServer
|
||||||
|
def handle_cast({:state, update}, {cfg, state}) do
|
||||||
|
{:noreply, {cfg, apply(update, [state])}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
37
lib/plugin/meta.ex
Normal file
37
lib/plugin/meta.ex
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
defmodule Omnibot.Plugin.Meta do
|
||||||
|
defmodule Hooks do
|
||||||
|
defmacro __before_compile(_env) do
|
||||||
|
quote do
|
||||||
|
def children(_cfg), do: []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defmacro __using__([]) do
|
||||||
|
quote do
|
||||||
|
use Omnibot.Plugin.Base
|
||||||
|
use Supervisor
|
||||||
|
|
||||||
|
@behaviour Omnibot.Plugin.Meta
|
||||||
|
|
||||||
|
## Client API
|
||||||
|
|
||||||
|
def start_link(opts) do
|
||||||
|
Supervisor.start_link(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
## Server callbacks
|
||||||
|
def init(opts) do
|
||||||
|
cfg = opts[:cfg]
|
||||||
|
children = children(cfg)
|
||||||
|
Supervisor.init(children, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
defoverridable Omnibot.Plugin.Meta
|
||||||
|
|
||||||
|
@before_compile Omnibot.Plugin.Meta.Hooks
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@callback children(cfg :: any) :: [{atom(), [{atom(), any}]}]
|
||||||
|
end
|
||||||
8
lib/plugin/plugin.ex
Normal file
8
lib/plugin/plugin.ex
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
defmodule Omnibot.Plugin do
|
||||||
|
defmacro __using__([]) do
|
||||||
|
quote do
|
||||||
|
use Omnibot.Plugin.Base
|
||||||
|
use Omnibot.Plugin.Agent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
40
lib/plugin/supervisor.ex
Normal file
40
lib/plugin/supervisor.ex
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
defmodule Omnibot.Plugin.Supervisor do
|
||||||
|
defmacro __using__(_opts) do
|
||||||
|
quote do
|
||||||
|
import Omnibot.Plugin.Supervisor
|
||||||
|
alias Omnibot.Plugin
|
||||||
|
use Supervisor
|
||||||
|
|
||||||
|
@behaviour Omnibot.Plugin.Supervisor
|
||||||
|
|
||||||
|
def start_link(opts) do
|
||||||
|
Supervisor.start_link(__MODULE__, opts[:cfg], opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def init(_cfg) do
|
||||||
|
Supervisor.init(children(), strategy: :one_for_one)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@callback children() :: [any]
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO :
|
||||||
|
# - figure out the best way to allow for including of supervisors and agents into a bot module
|
||||||
|
# - have to `use Agent` both places, this is not optimal
|
||||||
|
# - probably just lacks child_spec/1 ?
|
||||||
|
# - Do away with actual Plugin.Agent set of functions (outside of macro),
|
||||||
|
# and make it behaviours + `use Plugin.Agent` instead?
|
||||||
|
# Allow for ergonomic supervisor declarations, maybe like:
|
||||||
|
#
|
||||||
|
# Plugin.supervisor [
|
||||||
|
# SomeAgent,
|
||||||
|
# SomeGenSever,
|
||||||
|
# SomeWorker,
|
||||||
|
# ], strategy: one_for_all
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# And it implements all of the stuff for you? This may be too broad for how I'm doing things
|
||||||
|
# - rename MODULES to PLUGINS
|
||||||
Reference in New Issue
Block a user