defmodule IRC.PubSubHandler do @moduledoc """ # IRC PubSub Provides a nicer abstraction over ExIRC's handlers. ## PubSub topics * `message` -- all messages (including triggers) * `message:private` -- all messages without a channel * `message:#CHANNEL` -- all messages within `#CHANNEL` * `triggers` -- all triggers * `trigger:TRIGGER` -- any message with a trigger `TRIGGER` ## Replying to %IRC.Message{} Each `IRC.Message` comes with a dedicated `replyfun`, to which you only have to pass either: """ def irc_doc, do: nil def start_link(client) do GenServer.start_link(__MODULE__, [client], [name: __MODULE__]) end def init([client]) do ExIRC.Client.add_handler(client, self()) {:ok, client} end @triggers %{ "!" => :bang, "+" => :plus, "-" => :minus, "?" => :query, "." => :dot, } def handle_info({:received, text, sender, chan}, client) do reply_fun = fn(text) -> irc_reply(client, {chan, sender}, text) end message = %IRC.Message{text: text, sender: sender, channel: chan, replyfun: reply_fun, trigger: extract_trigger(text)} publish(message, ["message:#{chan}"]) {:noreply, client} end def handle_info({:received, text, sender}, client) do reply_fun = fn(text) -> irc_reply(client, {sender.nick, sender}, text) end message = %IRC.Message{text: text, sender: sender, replyfun: reply_fun, trigger: extract_trigger(text)} publish(message, ["message:private"]) {:noreply, client} end def handle_info(unhandled, client) do IO.puts inspect(unhandled) {:noreply, client} end defp publish(pub), do: publish(pub, []) defp publish(m = %IRC.Message{trigger: nil}, keys) do dispatch(["message"] ++ keys, {:irc, :text, m}) end defp publish(m = %IRC.Message{trigger: t = %IRC.Trigger{trigger: trigger}}, keys) do dispatch(["message", "triggers", "trigger:"<>trigger]++keys, {:irc, :trigger, trigger, m}) end defp dispatch(key, content) when is_binary(key), do: dispatch([key], content) defp dispatch(keys, content) when is_list(keys) do IO.puts "dispatching to #{inspect(keys)} --> #{inspect content}" for key <- keys do spawn(fn() -> Registry.dispatch(IRC.PubSub, key, fn h -> for {pid, _} <- h, do: send(pid, content) end) end) end end # # Triggers # for {trigger, name} <- @triggers do defp extract_trigger(unquote(trigger)<>text) do text = String.strip(text) [trigger | args] = String.split(text, " ") %IRC.Trigger{type: unquote(name), trigger: trigger, args: args} end end defp extract_trigger(_), do: nil # # IRC Replies # # irc_reply(ExIRC.Client pid, {channel or nick, ExIRC.Sender}, binary | replies # replies :: {:kick, reason} | {:kick, nick, reason} | {:mode, mode, nick} defp irc_reply(client, {target, _}, text) when is_binary(text) do ExIRC.Client.msg(client, :privmsg, target, text) end defp irc_reply(client, {target, %{nick: nick}}, {:kick, reason}) do ExIRC.Client.kick(client, target, nick, reason) end defp irc_reply(client, {target, _}, {:kick, nick, reason}) do ExIRC.Client.kick(client, target, nick, reason) end defp irc_reply(client, {target, %{nick: nick}}, {:mode, mode}) do ExIRC.Client.mode(client, target, mode, nick) end defp irc_reply(client, target, {:mode, mode, nick}) do ExIRC.Client.mode(client, target, mode, nick) end defp irc_reply(client, target, {:channel_mode, mode}) do ExIRC.Client.mode(client, target, mode) end end