Files
omnibot/lib/irc.ex
Alek Ratzloff 304a8d4164 WIP: Move Config.all_channels/0 and Config.channel_modules/1 logic into State; add State.add_loaded_module/2
The problem:

When we're going through the list of modules to send messages to based
on the channels they're a part of, it was being done so through the
config. Since the config doesn't (and shouldn't) list all of the core
modules that get included, any core modules that were loaded and running
under the ModuleSupervisor would not get included in the router's
attempt to send messages to a module.

Now, the Config.all_channels and Config.channel_modules functions live
in State, and State has a new "add_loaded_module" function where loaded
modules are registered. The aforementioned moved functions will use this
as the "source of truth" when deciding where to send messages for
modules to handle.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2020-06-13 17:13:05 -04:00

99 lines
2.4 KiB
Elixir

# REWRITE
defmodule Omnibot.Irc do
require Logger
alias Omnibot.Irc.Msg
alias Omnibot.{Config, State}
use GenServer
## Client API
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, :ok, opts)
end
def send_msg(irc, msg) do
GenServer.cast(irc, {:send_msg, msg})
end
def send_msg(irc, command, params) when is_list(params) do
cfg = State.cfg()
GenServer.cast(irc, {:send_msg, Config.msg(cfg, command, params)})
end
def send_msg(irc, command, param), do: send_msg(irc, command, [param])
def send_to(irc, channel, text), do: send_msg(irc, "PRIVMSG", [channel, text])
def join(irc, channel), do: send_msg(irc, "JOIN", channel)
def part(irc, channel), do: send_msg(irc, "PART", channel)
def sync_channels(irc), do: GenServer.cast(irc, :sync_channels)
## Server callbacks
@impl true
def init(:ok) do
cfg = State.cfg()
_ssl = cfg.ssl
{:ok, socket} =
:gen_tcp.connect(to_charlist(cfg.server), cfg.port, [:binary, active: false, packet: :line])
# Wait for first message
send_msg(self(), "NICK", cfg.nick)
send_msg(self(), "USER", [cfg.user, "0", "*", cfg.real])
:inet.setopts(socket, [active: true])
{:ok, socket}
end
defp write(socket, msg) do
msg = String.Chars.to_string(msg)
Logger.debug(">>> #{msg}")
:gen_tcp.send(socket, "#{msg}\r\n")
end
@impl true
def handle_cast({:send_msg, msg}, socket) do
write(socket, msg)
{:noreply, socket}
end
@impl true
def handle_cast({:tcp, line}, socket) do
Logger.debug(line)
{:noreply, socket}
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
def handle_info({:tcp, _socket, line}, socket) do
Logger.debug(String.trim(line))
msg = Msg.parse(line)
# Send the message to the router
irc = self()
{:ok, _task} = Task.Supervisor.start_child(
Omnibot.RouterSupervisor,
fn -> Omnibot.Router.route(irc, msg) end
)
{:noreply, socket}
end
end