Centralize logged messages marshaling

This allows messages added to logs to be handled just like messages
added to the ring buffer.
This commit is contained in:
Simon Ser 2020-04-07 19:45:29 +02:00
parent 37cd9e4d89
commit 3195809c30
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48
2 changed files with 53 additions and 84 deletions

View File

@ -222,17 +222,35 @@ func (dc *downstreamConn) SendMessage(msg *irc.Message) {
dc.conn.SendMessage(msg) dc.conn.SendMessage(msg)
} }
func (dc *downstreamConn) sendFromUpstream(msg *irc.Message, uc *upstreamConn) { // marshalMessage re-formats a message coming from an upstream connection so
// that it's suitable for being sent on this downstream connection. Only
// messages that may appear in logs are supported.
func (dc *downstreamConn) marshalMessage(msg *irc.Message, uc *upstreamConn) *irc.Message {
msg = msg.Copy() msg = msg.Copy()
msg.Prefix = dc.marshalUserPrefix(uc, msg.Prefix)
switch msg.Command { switch msg.Command {
case "PRIVMSG", "NOTICE": case "PRIVMSG", "NOTICE":
msg.Prefix = dc.marshalUserPrefix(uc, msg.Prefix)
msg.Params[0] = dc.marshalEntity(uc, msg.Params[0]) msg.Params[0] = dc.marshalEntity(uc, msg.Params[0])
case "NICK":
// Nick change for another user
msg.Params[0] = dc.marshalNick(uc, msg.Params[0])
case "JOIN", "PART":
msg.Params[0] = dc.marshalChannel(uc, msg.Params[0])
case "KICK":
msg.Params[0] = dc.marshalChannel(uc, msg.Params[0])
msg.Params[1] = dc.marshalNick(uc, msg.Params[1])
case "TOPIC":
msg.Params[0] = dc.marshalChannel(uc, msg.Params[0])
case "MODE":
msg.Params[0] = dc.marshalEntity(uc, msg.Params[0])
case "QUIT":
// This space is intentinally left blank
default: default:
panic(fmt.Sprintf("unexpected %q message", msg.Command)) panic(fmt.Sprintf("unexpected %q message", msg.Command))
} }
dc.SendMessage(msg) return msg
} }
func (dc *downstreamConn) handleMessage(msg *irc.Message) error { func (dc *downstreamConn) handleMessage(msg *irc.Message) error {
@ -684,7 +702,19 @@ func (dc *downstreamConn) welcome() error {
break break
} }
dc.sendFromUpstream(msg, uc) // Don't replay all messages, because that would mess up client
// state. For instance we just sent the list of users, sending
// PART messages for one of these users would be incorrect.
ignore := true
switch msg.Command {
case "PRIVMSG", "NOTICE":
ignore = false
}
if ignore {
continue
}
dc.SendMessage(dc.marshalMessage(msg, uc))
} }
}) })

View File

@ -562,12 +562,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
} }
if !me { if !me {
uc.network.ring.Produce(msg)
uc.forEachDownstream(func(dc *downstreamConn) { uc.forEachDownstream(func(dc *downstreamConn) {
dc.SendMessage(&irc.Message{ dc.SendMessage(dc.marshalMessage(msg, uc))
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "NICK",
Params: []string{dc.marshalEntity(uc, newNick)},
})
}) })
} }
case "JOIN": case "JOIN":
@ -601,15 +598,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
ch.Members[msg.Prefix.Name] = nil ch.Members[msg.Prefix.Name] = nil
} }
uc.appendLog(ch, msg) chMsg := msg.Copy()
chMsg.Params[0] = ch
uc.forEachDownstream(func(dc *downstreamConn) { uc.produce(ch, chMsg, nil)
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "JOIN",
Params: []string{dc.marshalChannel(uc, ch)},
})
})
} }
case "PART": case "PART":
if msg.Prefix == nil { if msg.Prefix == nil {
@ -621,11 +612,6 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
return err return err
} }
var reason string
if len(msg.Params) > 1 {
reason = msg.Params[1]
}
for _, ch := range strings.Split(channels, ",") { for _, ch := range strings.Split(channels, ",") {
if msg.Prefix.Name == uc.nick { if msg.Prefix.Name == uc.nick {
uc.logger.Printf("parted channel %q", ch) uc.logger.Printf("parted channel %q", ch)
@ -638,19 +624,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
delete(ch.Members, msg.Prefix.Name) delete(ch.Members, msg.Prefix.Name)
} }
uc.appendLog(ch, msg) chMsg := msg.Copy()
chMsg.Params[0] = ch
uc.forEachDownstream(func(dc *downstreamConn) { uc.produce(ch, chMsg, nil)
params := []string{dc.marshalChannel(uc, ch)}
if reason != "" {
params = append(params, reason)
}
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "PART",
Params: params,
})
})
} }
case "KICK": case "KICK":
if msg.Prefix == nil { if msg.Prefix == nil {
@ -662,11 +638,6 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
return err return err
} }
var reason string
if len(msg.Params) > 2 {
reason = msg.Params[2]
}
if user == uc.nick { if user == uc.nick {
uc.logger.Printf("kicked from channel %q by %s", channel, msg.Prefix.Name) uc.logger.Printf("kicked from channel %q by %s", channel, msg.Prefix.Name)
delete(uc.channels, channel) delete(uc.channels, channel)
@ -678,19 +649,7 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
delete(ch.Members, user) delete(ch.Members, user)
} }
uc.appendLog(channel, msg) uc.produce(channel, msg, nil)
uc.forEachDownstream(func(dc *downstreamConn) {
params := []string{dc.marshalChannel(uc, channel), dc.marshalNick(uc, user)}
if reason != "" {
params = append(params, reason)
}
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "KICK",
Params: params,
})
})
case "QUIT": case "QUIT":
if msg.Prefix == nil { if msg.Prefix == nil {
return fmt.Errorf("expected a prefix") return fmt.Errorf("expected a prefix")
@ -709,12 +668,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
} }
if msg.Prefix.Name != uc.nick { if msg.Prefix.Name != uc.nick {
uc.network.ring.Produce(msg)
uc.forEachDownstream(func(dc *downstreamConn) { uc.forEachDownstream(func(dc *downstreamConn) {
dc.SendMessage(&irc.Message{ dc.SendMessage(dc.marshalMessage(msg, uc))
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "QUIT",
Params: msg.Params,
})
}) })
} }
case irc.RPL_TOPIC, irc.RPL_NOTOPIC: case irc.RPL_TOPIC, irc.RPL_NOTOPIC:
@ -745,18 +701,7 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
} else { } else {
ch.Topic = "" ch.Topic = ""
} }
uc.appendLog(ch.Name, msg) uc.produce(ch.Name, msg, nil)
uc.forEachDownstream(func(dc *downstreamConn) {
params := []string{dc.marshalChannel(uc, name)}
if ch.Topic != "" {
params = append(params, ch.Topic)
}
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "TOPIC",
Params: params,
})
})
case "MODE": case "MODE":
var name, modeStr string var name, modeStr string
if err := parseMessageParams(msg, &name, &modeStr); err != nil { if err := parseMessageParams(msg, &name, &modeStr); err != nil {
@ -781,18 +726,7 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
} }
} }
uc.appendLog(ch.Name, msg) uc.produce(ch.Name, msg, nil)
uc.forEachDownstream(func(dc *downstreamConn) {
params := []string{dc.marshalChannel(uc, name), modeStr}
params = append(params, msg.Params[2:]...)
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "MODE",
Params: params,
})
})
} }
case irc.RPL_UMODEIS: case irc.RPL_UMODEIS:
if err := parseMessageParams(msg, nil); err != nil { if err := parseMessageParams(msg, nil); err != nil {
@ -1362,6 +1296,11 @@ func (uc *upstreamConn) appendLog(entity string, msg *irc.Message) {
} }
} }
// produce appends a message to the logs, adds it to the history and forwards
// it to connected downstream connections.
//
// If origin is not nil and origin doesn't support echo-message, the message is
// forwarded to all connections except origin.
func (uc *upstreamConn) produce(target string, msg *irc.Message, origin *downstreamConn) { func (uc *upstreamConn) produce(target string, msg *irc.Message, origin *downstreamConn) {
if target != "" { if target != "" {
uc.appendLog(target, msg) uc.appendLog(target, msg)
@ -1371,7 +1310,7 @@ func (uc *upstreamConn) produce(target string, msg *irc.Message, origin *downstr
uc.forEachDownstream(func(dc *downstreamConn) { uc.forEachDownstream(func(dc *downstreamConn) {
if dc != origin || dc.caps["echo-message"] { if dc != origin || dc.caps["echo-message"] {
dc.sendFromUpstream(msg, uc) dc.SendMessage(dc.marshalMessage(msg, uc))
} }
}) })
} }