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
124
125
126
127
128
129
130
131
132
133
134
135
|
defmodule IRC.PubSubHandler do
@moduledoc """
# IRC PubSub
Provides a nicer abstraction over ExIRC's handlers.
## PubSub topics
* `message` -- all messages (without 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 privmsg(channel, line) do
GenServer.cast(__MODULE__, {:privmsg, channel, line})
end
def init([client]) do
ExIRC.Client.add_handler(client, self())
{:ok, client}
end
@triggers %{
"!" => :bang,
"+" => :plus,
"-" => :minus,
"?" => :query,
"." => :dot,
"~" => :tilde
}
def handle_cast({:privmsg, channel, line}, client) do
irc_reply(client, {channel, nil}, line)
{:noreply, client}
end
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(["triggers", "trigger:"<>trigger], {: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) or is_list(text) do
for line <- IRC.splitlong(text) do
ExIRC.Client.msg(client, :privmsg, target, line)
end
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
|