Update modules to be more egonomic, add command macro
Modules are now defined using on_{msg,channel_msg,join,part,kick}.
Additionally, commands can be defined using a convenient macro.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -17,20 +17,15 @@ defmodule Omnibot.Contrib.Fortune do
|
||||
"Godly Luck",
|
||||
]
|
||||
|
||||
## Client API
|
||||
|
||||
def privmsg(module, channel, nick, line) do
|
||||
GenServer.cast(module, {:privmsg, {channel, nick, line}})
|
||||
command "!fortune", [to] do
|
||||
fortune = Enum.random(@fortunes)
|
||||
reply = "#{to}: #{fortune}"
|
||||
Irc.send_to(channel, reply)
|
||||
end
|
||||
|
||||
## Server callbacks
|
||||
|
||||
@impl true
|
||||
def on_channel_msg(channel, nick, line) do
|
||||
if line == "!fortune" do
|
||||
command "!fortune" do
|
||||
fortune = Enum.random(@fortunes)
|
||||
reply = "#{nick}: #{fortune}"
|
||||
Irc.send_to(channel, reply)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
133
lib/module.ex
133
lib/module.ex
@@ -1,72 +1,123 @@
|
||||
defmodule Omnibot.Module do
|
||||
defmodule Hooks do
|
||||
defmacro __before_compile__(_env) do
|
||||
quote do
|
||||
@impl true
|
||||
def on_channel_msg(_channel, _nick, _line), do: nil
|
||||
|
||||
@impl true
|
||||
def on_channel_msg(_channel, _nick, _cmd, _params), do: nil
|
||||
|
||||
@impl true
|
||||
def on_join(_channel, _nick), do: nil
|
||||
|
||||
@impl true
|
||||
def on_part(_channel, _nick), do: nil
|
||||
|
||||
@impl true
|
||||
def on_kick(_channel, _nick), do: nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmacro __using__([]) do
|
||||
quote do
|
||||
use GenServer
|
||||
use Agent
|
||||
alias Omnibot.{Irc, Module}
|
||||
import Omnibot.Module
|
||||
require Logger
|
||||
|
||||
@behaviour Module
|
||||
|
||||
## Client API
|
||||
|
||||
def start_link(opts) do
|
||||
GenServer.start_link(__MODULE__, opts[:cfg], opts ++ [name: __MODULE__])
|
||||
Agent.start_link(fn -> opts[:cfg] end, opts ++ [name: __MODULE__])
|
||||
end
|
||||
|
||||
def msg(msg), do: GenServer.cast(__MODULE__, msg)
|
||||
def msg(module, msg), do: GenServer.cast(module, {:msg, msg})
|
||||
|
||||
## Server callbacks
|
||||
|
||||
@impl GenServer
|
||||
def init(cfg), do: {:ok, cfg}
|
||||
def cfg do
|
||||
Agent.get(__MODULE__, & &1)
|
||||
end
|
||||
|
||||
@impl Module
|
||||
def on_msg(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(msg)
|
||||
end
|
||||
|
||||
def route_msg(msg) do
|
||||
defp route_msg(msg) do
|
||||
nick = msg.prefix.nick
|
||||
|
||||
case String.upcase(msg.command) do
|
||||
"PRIVMSG" -> [channel | text] = msg.params
|
||||
on_channel_msg(channel, nick, Enum.join(text, " "))
|
||||
"JOIN" -> [channel | _] = msg.params
|
||||
"PRIVMSG" ->
|
||||
[channel | params] = msg.params
|
||||
line = Enum.join(params, " ")
|
||||
|
||||
case String.split(line, " ") do
|
||||
[cmd | params] -> on_channel_msg(channel, nick, cmd, params)
|
||||
_ -> on_channel_msg(channel, nick, line)
|
||||
end
|
||||
|
||||
"JOIN" ->
|
||||
[channel | _] = msg.params
|
||||
on_join(channel, nick)
|
||||
"PART" -> [channel | _] = msg.params
|
||||
|
||||
"PART" ->
|
||||
[channel | _] = msg.params
|
||||
on_part(channel, nick)
|
||||
"KICK" -> [channel | _] = msg.params
|
||||
|
||||
"KICK" ->
|
||||
[channel | _] = msg.params
|
||||
on_kick(channel, nick)
|
||||
_ -> nil
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@impl Module
|
||||
def on_channel_msg(_channel, _nick, _line), do: nil
|
||||
|
||||
@impl Module
|
||||
def on_join(_channel, _nick), do: nil
|
||||
|
||||
@impl Module
|
||||
def on_part(_channel, _nick), do: nil
|
||||
|
||||
@impl Module
|
||||
def on_kick(_channel, _nick), do: nil
|
||||
|
||||
@impl GenServer
|
||||
def handle_cast({:msg, msg}, cfg) do
|
||||
on_msg(msg)
|
||||
{:noreply, cfg}
|
||||
end
|
||||
|
||||
defoverridable Module
|
||||
defoverridable GenServer
|
||||
|
||||
@before_compile Omnibot.Module.Hooks
|
||||
end
|
||||
end
|
||||
|
||||
@callback on_msg(msg :: %Omnibot.Irc.Msg{}) :: any
|
||||
@callback on_channel_msg(channel :: String.t, nick :: String.t, line :: String.t) :: any
|
||||
@callback on_join(channel :: String.t, nick :: String.t) :: any
|
||||
@callback on_part(channel :: String.t, nick :: String.t) :: any
|
||||
@callback on_kick(channel :: String.t, nick :: String.t) :: any
|
||||
@callback on_channel_msg(channel :: String.t(), nick :: String.t(), line :: String.t()) :: any
|
||||
@callback on_channel_msg(
|
||||
channel :: String.t(),
|
||||
nick :: String.t(),
|
||||
cmd :: String.t(),
|
||||
params :: [String.t()]
|
||||
) :: any
|
||||
@callback on_join(channel :: String.t(), nick :: String.t()) :: any
|
||||
@callback on_part(channel :: String.t(), nick :: String.t()) :: any
|
||||
@callback on_kick(channel :: String.t(), nick :: String.t()) :: any
|
||||
|
||||
defmacro command(cmd, opts) do
|
||||
quote generated: true do
|
||||
@impl Omnibot.Module
|
||||
def on_channel_msg(var!(channel), var!(nick), unquote(cmd), var!(params)) do
|
||||
unquote(opts[:do])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmacro command(cmd, params, opts) do
|
||||
params =
|
||||
Enum.map(
|
||||
IO.inspect(params),
|
||||
fn param ->
|
||||
case param do
|
||||
{_, _, _} -> quote(do: var!(unquote(param)))
|
||||
lit -> Macro.escape(lit)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
quote generated: true do
|
||||
@impl Omnibot.Module
|
||||
def on_channel_msg(var!(channel), var!(nick), unquote(cmd), unquote(params)) do
|
||||
unquote(opts[:do])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ defmodule Omnibot.Router do
|
||||
# Find modules that want this message
|
||||
State.cfg()
|
||||
|> Config.channel_modules(channel)
|
||||
|> Enum.each(fn {module, _} -> module.msg(module, msg) end)
|
||||
|> Enum.each(fn {module, _} -> module.on_msg(msg) end)
|
||||
end
|
||||
|
||||
def handle(_irc, :join, %Msg {prefix: %Msg.Prefix{nick: nick}, params: [channel | _]}) do
|
||||
|
||||
Reference in New Issue
Block a user