diff options
Diffstat (limited to 'lib/irc/pubsub_handler.ex')
-rw-r--r-- | lib/irc/pubsub_handler.ex | 123 |
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 |