blob: 07d978c2a1524027c8cb007b7edd3a21fece9484 [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) {
Michal Zagorski5b1aa132020-03-01 17:05:05 +010080 glog.V(16).Infof("event/debug16: New event handling")
Sergiusz Bazanskia8854882020-01-05 00:34:38 +010081 switch {
82 case e.nick != nil:
Michal Zagorski5b1aa132020-03-01 17:05:05 +010083 glog.V(8).Infof("event/debug8: nick (%s)", e.nick.nick)
Sergiusz Bazanskia8854882020-01-05 00:34:38 +010084 // Nick update from connection
85
86 // Ensure this connection is still used.
87 if m.conns[e.nick.conn.user] != e.nick.conn {
88 return
89 }
90
91 // Edge-detect changes.
92 changed := false
93 if m.nickmap[e.nick.conn.user] != e.nick.nick {
94 glog.Infof("Event: Nick change for %s: %q -> %q", e.nick.conn.user, m.nickmap[e.nick.conn.user], e.nick.nick)
95 m.nickmap[e.nick.conn.user] = e.nick.nick
96 changed = true
97 }
98
99 if !changed {
100 return
101 }
102
103 // Notify subscribers about a new nickmap.
104 nm := make(map[string]string)
105 for k, v := range m.nickmap {
106 nm[k] = v
107 }
108 m.notifyAll(&Notification{
109 Nickmap: &nm,
110 })
111
112 case e.banned != nil:
113 // A connection is banned. Shitlist the given user to not retry again.
114 user := e.banned.conn.user
115 glog.Infof("Event: %s is banned!", user)
116 m.shitlist[user] = time.Now().Add(time.Hour)
117
118 case e.dead != nil:
119 // Dead update from connection.
120
121 // Ensure this connection is still used.
122 if m.conns[e.dead.conn.user] != e.dead.conn {
123 return
124 }
125
126 // Delete connection.
127 glog.Infof("Event: Connection for %s died", e.dead.conn.user)
128 delete(m.conns, e.dead.conn.user)
129
130 case e.message != nil:
131 // Route messages from receivers.
132
133 // Drop non-receiver events.
134 if !e.message.conn.receiver {
135 return
136 }
137
138 // Ensure this is not from us.
139 for _, i := range m.nickmap {
140 if e.message.nick == i {
141 return
142 }
143 }
144
145 m.notifyAll(&Notification{
146 Message: &NotificationMessage{
147 Nick: e.message.nick,
148 Message: e.message.message,
149 },
150 })
151
152 default:
153 glog.Errorf("Event: Unhandled event %+v", e)
154 }
155}