1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
|