summaryrefslogtreecommitdiff
path: root/lib/irc/pubsub_handler.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/irc/pubsub_handler.ex')
-rw-r--r--lib/irc/pubsub_handler.ex123
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/irc/pubsub_handler.ex b/lib/irc/pubsub_handler.ex
new file mode 100644
index 0000000..3e78d7b
--- /dev/null
+++ b/lib/irc/pubsub_handler.ex
@@ -0,0 +1,123 @@
+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