~emersion/soju

349f46d1858b2c79f3464db5ceabe4bfe0ad3aad — Simon Ser 4 days ago e3d7c33 motd-queue
Use queue mechanism to route MOTD replies
2 files changed, 40 insertions(+), 26 deletions(-)

M downstream.go
M upstream.go
M downstream.go => downstream.go +26 -16
@@ 1328,22 1328,7 @@ func (dc *downstreamConn) welcome(ctx context.Context) error {
	dc.updateNick()
	dc.updateRealname()
	dc.updateAccount()

	if motd := dc.user.srv.Config().MOTD; motd != "" && dc.network == nil {
		for _, msg := range generateMOTD(dc.srv.prefix(), dc.nick, motd) {
			dc.SendMessage(msg)
		}
	} else {
		motdHint := "No MOTD"
		if dc.network != nil {
			motdHint = "Use /motd to read the message of the day"
		}
		dc.SendMessage(&irc.Message{
			Prefix:  dc.srv.prefix(),
			Command: irc.ERR_NOMOTD,
			Params:  []string{dc.nick, motdHint},
		})
	}
	dc.sendMOTD()

	if dc.caps["soju.im/bouncer-networks-notify"] {
		dc.SendBatch("soju.im/bouncer-networks", nil, nil, func(batchRef irc.TagValue) {


@@ 2400,6 2385,13 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
				Params:  []string{"PLAIN"},
			})
		}
	case "MOTD":
		uc := dc.upstream()
		if uc == nil {
			dc.sendMOTD()
			return nil
		}
		uc.enqueueCommand(dc, &irc.Message{Command: "MOTD"})
	case "MONITOR":
		// MONITOR is unsupported in multi-upstream mode
		uc := dc.upstream()


@@ 2768,6 2760,24 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
	return nil
}

func (dc *downstreamConn) sendMOTD() {
	if motd := dc.user.srv.Config().MOTD; motd != "" && dc.network == nil {
		for _, msg := range generateMOTD(dc.srv.prefix(), dc.nick, motd) {
			dc.SendMessage(msg)
		}
	} else {
		motdHint := "No MOTD"
		if dc.network != nil {
			motdHint = "Use /motd to read the message of the day"
		}
		dc.SendMessage(&irc.Message{
			Prefix:  dc.srv.prefix(),
			Command: irc.ERR_NOMOTD,
			Params:  []string{dc.nick, motdHint},
		})
	}
}

func (dc *downstreamConn) handleNickServPRIVMSG(ctx context.Context, uc *upstreamConn, text string) {
	username, password, ok := parseNickServCredentials(text, uc.nick)
	if ok {

M upstream.go => upstream.go +14 -10
@@ 300,6 300,12 @@ func (uc *upstreamConn) endPendingCommands() {
					Command: irc.ERR_SASLABORTED,
					Params:  []string{dc.nick, "SASL authentication aborted"},
				})
			case "MOTD":
				dc.SendMessage(&irc.Message{
					Prefix:  dc.srv.prefix(),
					Command: irc.ERR_NOMOTD,
					Params:  []string{dc.nick, "No MOTD"},
				})
			default:
				panic(fmt.Errorf("Unsupported pending command %q", pendingCmd.msg.Command))
			}


@@ 318,7 324,7 @@ func (uc *upstreamConn) sendNextPendingCommand(cmd string) {

func (uc *upstreamConn) enqueueCommand(dc *downstreamConn, msg *irc.Message) {
	switch msg.Command {
	case "LIST", "WHO", "AUTHENTICATE":
	case "LIST", "WHO", "AUTHENTICATE", "MOTD":
		// Supported
	default:
		panic(fmt.Errorf("Unsupported pending command %q", msg.Command))


@@ 727,6 733,10 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
				dc.SendMessage(msg)
			}
		})
	case irc.RPL_MOTDSTART, irc.RPL_MOTD:
		if dc, _ := uc.currentPendingCommand("MOTD"); dc != nil {
			dc.SendMessage(msg)
		}
	case irc.ERR_NOMOTD, irc.RPL_ENDOFMOTD:
		if !uc.casemapIsSet {
			// upstream did not send any CASEMAPPING token, thus


@@ 743,13 753,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
			return nil
		}

		uc.forEachDownstreamByID(downstreamID, func(dc *downstreamConn) {
			dc.SendMessage(&irc.Message{
				Prefix:  uc.srv.prefix(),
				Command: msg.Command,
				Params:  msg.Params,
			})
		})
		if dc, _ := uc.dequeueCommand("MOTD"); dc != nil {
			dc.SendMessage(msg)
		}
	case "BATCH":
		var tag string
		if err := parseMessageParams(msg, &tag); err != nil {


@@ 1594,8 1600,6 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
	case irc.RPL_STATSVLINE, rpl_statsping, irc.RPL_STATSBLINE, irc.RPL_STATSDLINE:
		fallthrough
	case rpl_localusers, rpl_globalusers:
		fallthrough
	case irc.RPL_MOTDSTART, irc.RPL_MOTD:
		// Ignore these messages if they're part of the initial registration
		// message burst. Forward them if the user explicitly asked for them.
		if !uc.gotMotd {