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)
}
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.Prefix = dc.marshalUserPrefix(uc, msg.Prefix)
switch msg.Command {
case "PRIVMSG", "NOTICE":
msg.Prefix = dc.marshalUserPrefix(uc, msg.Prefix)
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:
panic(fmt.Sprintf("unexpected %q message", msg.Command))
}
dc.SendMessage(msg)
return msg
}
func (dc *downstreamConn) handleMessage(msg *irc.Message) error {
@ -684,7 +702,19 @@ func (dc *downstreamConn) welcome() error {
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 {
uc.network.ring.Produce(msg)
uc.forEachDownstream(func(dc *downstreamConn) {
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "NICK",
Params: []string{dc.marshalEntity(uc, newNick)},
})
dc.SendMessage(dc.marshalMessage(msg, uc))
})
}
case "JOIN":
@ -601,15 +598,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
ch.Members[msg.Prefix.Name] = nil
}
uc.appendLog(ch, msg)
uc.forEachDownstream(func(dc *downstreamConn) {
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "JOIN",
Params: []string{dc.marshalChannel(uc, ch)},
})
})
chMsg := msg.Copy()
chMsg.Params[0] = ch
uc.produce(ch, chMsg, nil)
}
case "PART":
if msg.Prefix == nil {
@ -621,11 +612,6 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
return err
}
var reason string
if len(msg.Params) > 1 {
reason = msg.Params[1]
}
for _, ch := range strings.Split(channels, ",") {
if msg.Prefix.Name == uc.nick {
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)
}
uc.appendLog(ch, msg)
uc.forEachDownstream(func(dc *downstreamConn) {
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,
})
})
chMsg := msg.Copy()
chMsg.Params[0] = ch
uc.produce(ch, chMsg, nil)
}
case "KICK":
if msg.Prefix == nil {
@ -662,11 +638,6 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
return err
}
var reason string
if len(msg.Params) > 2 {
reason = msg.Params[2]
}
if user == uc.nick {
uc.logger.Printf("kicked from channel %q by %s", channel, msg.Prefix.Name)
delete(uc.channels, channel)
@ -678,19 +649,7 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
delete(ch.Members, user)
}
uc.appendLog(channel, msg)
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,
})
})
uc.produce(channel, msg, nil)
case "QUIT":
if msg.Prefix == nil {
return fmt.Errorf("expected a prefix")
@ -709,12 +668,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
}
if msg.Prefix.Name != uc.nick {
uc.network.ring.Produce(msg)
uc.forEachDownstream(func(dc *downstreamConn) {
dc.SendMessage(&irc.Message{
Prefix: dc.marshalUserPrefix(uc, msg.Prefix),
Command: "QUIT",
Params: msg.Params,
})
dc.SendMessage(dc.marshalMessage(msg, uc))
})
}
case irc.RPL_TOPIC, irc.RPL_NOTOPIC:
@ -745,18 +701,7 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
} else {
ch.Topic = ""
}
uc.appendLog(ch.Name, msg)
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,
})
})
uc.produce(ch.Name, msg, nil)
case "MODE":
var name, modeStr string
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.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,
})
})
uc.produce(ch.Name, msg, nil)
}
case irc.RPL_UMODEIS:
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) {
if target != "" {
uc.appendLog(target, msg)
@ -1371,7 +1310,7 @@ func (uc *upstreamConn) produce(target string, msg *irc.Message, origin *downstr
uc.forEachDownstream(func(dc *downstreamConn) {
if dc != origin || dc.caps["echo-message"] {
dc.sendFromUpstream(msg, uc)
dc.SendMessage(dc.marshalMessage(msg, uc))
}
})
}