Move more stuff from other places into Omnibot.Core
* Present rooms are tracked by Omnibot.Core now, instead of Omnibot.State * Channel synchronization is done through Omnibot.Core instead of Omnibot.Irc * Add Omnibot.Module.on_init/1 callback, which returns a "state" value for the module to keep track of. By default, the state is nil. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
43
lib/core.ex
43
lib/core.ex
@@ -2,42 +2,71 @@ defmodule Omnibot.Core do
|
|||||||
use Omnibot.Module
|
use Omnibot.Module
|
||||||
alias Omnibot.State
|
alias Omnibot.State
|
||||||
|
|
||||||
|
@impl true
|
||||||
def on_join(irc, channel, nick) do
|
def on_join(irc, channel, nick) do
|
||||||
cfg = State.cfg()
|
cfg = State.cfg()
|
||||||
if nick == cfg.nick do
|
if nick == cfg.nick do
|
||||||
State.add_channel(channel)
|
add_channel(channel)
|
||||||
# Sync if we join a channel we shouldn't be in
|
# Sync if we join a channel we shouldn't be in
|
||||||
if !Enum.member?(State.all_channels(), channel),
|
if !Enum.member?(State.all_channels(), channel),
|
||||||
do: Irc.sync_channels(irc)
|
do: sync_channels(irc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def on_part(irc, channel, nick) do
|
def on_part(irc, channel, nick) do
|
||||||
cfg = State.cfg()
|
cfg = State.cfg()
|
||||||
if nick == cfg.nick do
|
if nick == cfg.nick do
|
||||||
State.remove_channel(channel)
|
remove_channel(channel)
|
||||||
# Sync if we join a channel we forcibly part a channel we shouldn't leave
|
# Sync if we join a channel we forcibly part a channel we shouldn't leave
|
||||||
if Enum.member?(State.all_channels(), channel),
|
if Enum.member?(State.all_channels(), channel),
|
||||||
do: Irc.sync_channels(irc)
|
do: sync_channels(irc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def on_kick(irc, channel, _nick, target) do
|
def on_kick(irc, channel, _nick, target) do
|
||||||
cfg = State.cfg()
|
cfg = State.cfg()
|
||||||
if target == cfg.nick do
|
if target == cfg.nick do
|
||||||
State.remove_channel(channel)
|
remove_channel(channel)
|
||||||
# Generally, being kicked is not intentionally leaving a channel, so always sync here
|
# Generally, being kicked is not intentionally leaving a channel, so always sync here
|
||||||
Irc.sync_channels(irc)
|
sync_channels(irc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def on_msg(irc, msg) do
|
def on_msg(irc, msg) do
|
||||||
case String.upcase(msg.command) do
|
case String.upcase(msg.command) do
|
||||||
"001" -> Irc.sync_channels(irc)
|
"001" -> sync_channels(irc)
|
||||||
"PING" -> Irc.send_msg(irc, "PONG", msg.params)
|
"PING" -> Irc.send_msg(irc, "PONG", msg.params)
|
||||||
_ -> route_msg(irc, msg)
|
_ -> route_msg(irc, msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_init(_cfg) do
|
||||||
|
MapSet.new()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sync_channels(irc) do
|
||||||
|
desired = MapSet.new(State.all_channels())
|
||||||
|
present = state()
|
||||||
|
|
||||||
|
to_join = MapSet.difference(desired, present)
|
||||||
|
|> MapSet.to_list()
|
||||||
|
to_part = MapSet.difference(present, desired)
|
||||||
|
|> MapSet.to_list()
|
||||||
|
|
||||||
|
Enum.each(to_join, fn channel -> Irc.join(irc, channel) end)
|
||||||
|
Enum.each(to_part, fn channel -> Irc.part(irc, channel) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp add_channel(channel) do
|
||||||
|
update_state(fn state -> MapSet.put(state, channel) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp remove_channel(channel) do
|
||||||
|
update_state(fn state -> MapSet.delete(state, channel) end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
18
lib/irc.ex
18
lib/irc.ex
@@ -28,8 +28,6 @@ defmodule Omnibot.Irc do
|
|||||||
|
|
||||||
def part(irc, channel), do: send_msg(irc, "PART", channel)
|
def part(irc, channel), do: send_msg(irc, "PART", channel)
|
||||||
|
|
||||||
def sync_channels(irc), do: GenServer.cast(irc, :sync_channels)
|
|
||||||
|
|
||||||
defp route_msg(irc, msg) do
|
defp route_msg(irc, msg) do
|
||||||
channel = Msg.channel(msg)
|
channel = Msg.channel(msg)
|
||||||
State.channel_modules(channel)
|
State.channel_modules(channel)
|
||||||
@@ -72,22 +70,6 @@ defmodule Omnibot.Irc do
|
|||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_cast(:sync_channels, socket) do
|
|
||||||
cfg = State.cfg()
|
|
||||||
desired = MapSet.new(Config.all_channels(cfg))
|
|
||||||
present = MapSet.new(State.channels())
|
|
||||||
to_join = MapSet.difference(desired, present)
|
|
||||||
|> MapSet.to_list()
|
|
||||||
to_part = MapSet.difference(present, desired)
|
|
||||||
|> MapSet.to_list()
|
|
||||||
|
|
||||||
Enum.each(to_join, fn channel -> join(self(), channel) end)
|
|
||||||
Enum.each(to_part, fn channel -> part(self(), channel) end)
|
|
||||||
|
|
||||||
{:noreply, socket}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:tcp, _socket, line}, socket) do
|
def handle_info({:tcp, _socket, line}, socket) do
|
||||||
Logger.debug(String.trim(line))
|
Logger.debug(String.trim(line))
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ defmodule Omnibot.Module do
|
|||||||
def on_part(_irc, _channel, _nick), do: nil
|
def on_part(_irc, _channel, _nick), do: nil
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def on_kick(_irc, _channel, _nick), do: nil
|
def on_kick(_irc, _channel, _nick, _target), do: nil
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def on_init(_cfg), do: nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -30,11 +33,24 @@ defmodule Omnibot.Module do
|
|||||||
@behaviour Module
|
@behaviour Module
|
||||||
|
|
||||||
def start_link(opts) do
|
def start_link(opts) do
|
||||||
Agent.start_link(fn -> opts[:cfg] end, opts ++ [name: __MODULE__])
|
cfg = opts[:cfg]
|
||||||
|
Agent.start_link(fn -> {cfg, on_init(cfg)} end, opts ++ [name: __MODULE__])
|
||||||
end
|
end
|
||||||
|
|
||||||
def cfg do
|
def cfg do
|
||||||
Agent.get(__MODULE__, & &1)
|
Agent.get(__MODULE__, fn {cfg, _} -> cfg end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def state do
|
||||||
|
Agent.get(__MODULE__, fn {_, state} -> state end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_state(update, timeout \\ 5000) do
|
||||||
|
Agent.update(
|
||||||
|
__MODULE__,
|
||||||
|
fn {cfg, state} -> {cfg, apply(update, [state])} end,
|
||||||
|
timeout
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl Module
|
@impl Module
|
||||||
@@ -66,8 +82,8 @@ defmodule Omnibot.Module do
|
|||||||
on_part(irc, channel, nick)
|
on_part(irc, channel, nick)
|
||||||
|
|
||||||
"KICK" ->
|
"KICK" ->
|
||||||
[channel | _] = msg.params
|
[channel, target | _] = msg.params
|
||||||
on_kick(irc, channel, nick)
|
on_kick(irc, channel, nick, target)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
nil
|
nil
|
||||||
@@ -91,7 +107,8 @@ defmodule Omnibot.Module do
|
|||||||
) :: any
|
) :: any
|
||||||
@callback on_join(irc :: pid(), channel :: String.t(), nick :: 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_part(irc :: pid(), channel :: String.t(), nick :: String.t()) :: any
|
||||||
@callback on_kick(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
|
||||||
|
|
||||||
defmacro command(cmd, opts) do
|
defmacro command(cmd, opts) do
|
||||||
quote generated: true do
|
quote generated: true do
|
||||||
|
|||||||
39
lib/state.ex
39
lib/state.ex
@@ -36,30 +36,6 @@ defmodule Omnibot.State do
|
|||||||
@doc "Gets all loaded modules from the given state."
|
@doc "Gets all loaded modules from the given state."
|
||||||
def loaded_modules(state), do: GenServer.call(state, :loaded_modules)
|
def loaded_modules(state), do: GenServer.call(state, :loaded_modules)
|
||||||
|
|
||||||
@doc "Gets all channels that the bot is present in from the default State process."
|
|
||||||
def channels(), do: channels(__MODULE__)
|
|
||||||
|
|
||||||
@doc "Gets all channels that the bot is present in from the given State process."
|
|
||||||
def channels(state) do
|
|
||||||
GenServer.call(state, :channels)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Adds a channel to the list of joined channels of the default State process, if it is not already present."
|
|
||||||
def add_channel(channel), do: add_channel(__MODULE__, channel)
|
|
||||||
|
|
||||||
@doc "Adds a channel to the list of joined channels of the given State process, if it is not already present."
|
|
||||||
def add_channel(state, channel) do
|
|
||||||
GenServer.cast(state, {:add_channel, channel})
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Removes a channel from the list of joined channels of the default State process, if it exists."
|
|
||||||
def remove_channel(channel), do: remove_channel(__MODULE__, channel)
|
|
||||||
|
|
||||||
@doc "Removes a channel from the list of joined channels of the given State process, if it exists."
|
|
||||||
def remove_channel(state, channel) do
|
|
||||||
GenServer.cast(state, {:remove_channel, channel})
|
|
||||||
end
|
|
||||||
|
|
||||||
def all_channels(), do: all_channels(__MODULE__)
|
def all_channels(), do: all_channels(__MODULE__)
|
||||||
|
|
||||||
def all_channels(state) do
|
def all_channels(state) do
|
||||||
@@ -100,11 +76,6 @@ defmodule Omnibot.State do
|
|||||||
{:reply, state.cfg, state}
|
{:reply, state.cfg, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_call(:channels, _from, state) do
|
|
||||||
{:reply, state.channels, state}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_call(:loaded_modules, _from, state) do
|
def handle_call(:loaded_modules, _from, state) do
|
||||||
{:reply, state.module_map, state}
|
{:reply, state.module_map, state}
|
||||||
@@ -115,14 +86,4 @@ defmodule Omnibot.State do
|
|||||||
state = %{state | module_map: Map.put(state.module_map, module, cfg)}
|
state = %{state | module_map: Map.put(state.module_map, module, cfg)}
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_cast({:add_channel, channel}, state) do
|
|
||||||
{:noreply, %{state | channels: state.channels |> MapSet.put(channel)}}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_cast({:remove_channel, channel}, state) do
|
|
||||||
{:noreply, %{state | channels: state.channels |> MapSet.delete(channel)}}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user