blob: 399915ca3abe37b7fb8aaa42094566bbe7827cb8 [file] [log] [blame]
Sergiusz Bazanskia8854882020-01-05 00:34:38 +01001package irc
2
3import (
4 "context"
5 "time"
6
7 "github.com/golang/glog"
8)
9
10func (m *Manager) Event(e *event) {
11 m.event <- e
12}
13
14// Event: a connection has a new nick.
15func (m *Manager) UpdateNickmap(conn *ircconn, nick string) {
16 m.event <- &event{
17 nick: &eventNick{
18 conn: conn,
19 nick: nick,
20 },
21 }
22}
23
24// Event: mark a given connection as dead.
25func (m *Manager) MarkDead(i *ircconn) {
26 m.event <- &event{
27 dead: &eventDead{
28 conn: i,
29 },
30 }
31}
32
33// event message from IRC connections. Only one member can be set.
34type event struct {
35 // a connection has gotten a (new) nick
36 nick *eventNick
37 // a connection received a new PRIVMSG
38 message *eventMessage
39 // a connection is banned
40 banned *eventBanned
41 // a connection died
42 dead *eventDead
43}
44
45// eventNick is emitted when a connection has received a new nickname from IRC
46type eventNick struct {
47 conn *ircconn
48 nick string
49}
50
51// eventMessage is emitted when there is a PRIVMSG to the IRC channel. This
52// does not contain messages sent by ourselves, and messages are deduplicated
53// from multiple active IRC connections.
54type eventMessage struct {
55 conn *ircconn
56 nick string
57 message string
58}
59
60// eventBanned is amitted when a connection is banned from a channel.
61type eventBanned struct {
62 conn *ircconn
63}
64
65// eventDead is emitted when a connection has died and needs to be disposed of
66type eventDead struct {
67 conn *ircconn
68}
69
70func (m *Manager) notifyAll(n *Notification) {
71 for s, _ := range m.subscribers {
72 go func(c chan *Notification, n *Notification) {
73 c <- n
74 }(s, n)
75 }
76}
77
78// doevent handles incoming events.
79func (m *Manager) doevent(ctx context.Context, e *event) {
80 switch {
81 case e.nick != nil:
82 // Nick update from connection
83
84 // Ensure this connection is still used.
85 if m.conns[e.nick.conn.user] != e.nick.conn {
86 return
87 }
88
89 // Edge-detect changes.
90 changed := false
91 if m.nickmap[e.nick.conn.user] != e.nick.nick {
92 glog.Infof("Event: Nick change for %s: %q -> %q", e.nick.conn.user, m.nickmap[e.nick.conn.user], e.nick.nick)
93 m.nickmap[e.nick.conn.user] = e.nick.nick
94 changed = true
95 }
96
97 if !changed {
98 return
99 }
100
101 // Notify subscribers about a new nickmap.
102 nm := make(map[string]string)
103 for k, v := range m.nickmap {
104 nm[k] = v
105 }
106 m.notifyAll(&Notification{
107 Nickmap: &nm,
108 })
109
110 case e.banned != nil:
111 // A connection is banned. Shitlist the given user to not retry again.
112 user := e.banned.conn.user
113 glog.Infof("Event: %s is banned!", user)
114 m.shitlist[user] = time.Now().Add(time.Hour)
115
116 case e.dead != nil:
117 // Dead update from connection.
118
119 // Ensure this connection is still used.
120 if m.conns[e.dead.conn.user] != e.dead.conn {
121 return
122 }
123
124 // Delete connection.
125 glog.Infof("Event: Connection for %s died", e.dead.conn.user)
126 delete(m.conns, e.dead.conn.user)
127
128 case e.message != nil:
129 // Route messages from receivers.
130
131 // Drop non-receiver events.
132 if !e.message.conn.receiver {
133 return
134 }
135
136 // Ensure this is not from us.
137 for _, i := range m.nickmap {
138 if e.message.nick == i {
139 return
140 }
141 }
142
143 m.notifyAll(&Notification{
144 Message: &NotificationMessage{
145 Nick: e.message.nick,
146 Message: e.message.message,
147 },
148 })
149
150 default:
151 glog.Errorf("Event: Unhandled event %+v", e)
152 }
153}