Changeset 684 in code for trunk/upstream.go


Ignore:
Timestamp:
Nov 15, 2021, 1:34:04 PM (4 years ago)
Author:
contact
Message:

Add support for MONITOR

Add support for MONITOR in single-upstream mode.

Each downstream has its own set of monitored targets. These sets
are merged together to compute the MONITOR commands to send to
upstream.

Each upstream has a set of monitored targets accepted by the server
alongside with their status (online/offline). This is used to
directly send replies to downstreams adding a target another
downstream has already added, and send MONITOR S[TATUS] replies.

Co-authored-by: delthas <delthas@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/upstream.go

    r682 r684  
    104104        account       string
    105105        nextLabelID   uint64
     106        monitored     monitorCasemapMap
    106107
    107108        saslClient  sasl.Client
     
    210211                isupport:              make(map[string]*string),
    211212                pendingCmds:           make(map[string][]pendingUpstreamCommand),
     213                monitored:             monitorCasemapMap{newCasemapMap(0)},
    212214        }
    213215        return uc, nil
     
    14141416                        })
    14151417                })
     1418        case irc.RPL_MONONLINE, irc.RPL_MONOFFLINE:
     1419                var targetsStr string
     1420                if err := parseMessageParams(msg, nil, &targetsStr); err != nil {
     1421                        return err
     1422                }
     1423                targets := strings.Split(targetsStr, ",")
     1424
     1425                online := msg.Command == irc.RPL_MONONLINE
     1426                for _, target := range targets {
     1427                        prefix := irc.ParsePrefix(target)
     1428                        uc.monitored.SetValue(prefix.Name, online)
     1429                }
     1430
     1431                uc.forEachDownstream(func(dc *downstreamConn) {
     1432                        for _, target := range targets {
     1433                                prefix := irc.ParsePrefix(target)
     1434                                if dc.monitored.Has(prefix.Name) {
     1435                                        dc.SendMessage(&irc.Message{
     1436                                                Prefix:  dc.srv.prefix(),
     1437                                                Command: msg.Command,
     1438                                                Params:  []string{dc.nick, target},
     1439                                        })
     1440                                }
     1441                        }
     1442                })
     1443        case irc.ERR_MONLISTFULL:
     1444                var limit, targetsStr string
     1445                if err := parseMessageParams(msg, nil, &limit, &targetsStr); err != nil {
     1446                        return err
     1447                }
     1448
     1449                targets := strings.Split(targetsStr, ",")
     1450                uc.forEachDownstream(func(dc *downstreamConn) {
     1451                        for _, target := range targets {
     1452                                if dc.monitored.Has(target) {
     1453                                        dc.SendMessage(&irc.Message{
     1454                                                Prefix:  dc.srv.prefix(),
     1455                                                Command: msg.Command,
     1456                                                Params:  []string{dc.nick, limit, target},
     1457                                        })
     1458                                }
     1459                        }
     1460                })
    14161461        case irc.RPL_AWAY:
    14171462                var nick, reason string
     
    19131958        uch.updateAutoDetach(ch.DetachAfter)
    19141959}
     1960
     1961func (uc *upstreamConn) updateMonitor() {
     1962        add := make(map[string]struct{})
     1963        var addList []string
     1964        seen := make(map[string]struct{})
     1965        uc.forEachDownstream(func(dc *downstreamConn) {
     1966                for targetCM := range dc.monitored.innerMap {
     1967                        if !uc.monitored.Has(targetCM) {
     1968                                if _, ok := add[targetCM]; !ok {
     1969                                        addList = append(addList, targetCM)
     1970                                }
     1971                                add[targetCM] = struct{}{}
     1972                        } else {
     1973                                seen[targetCM] = struct{}{}
     1974                        }
     1975                }
     1976        })
     1977
     1978        removeAll := true
     1979        var removeList []string
     1980        for targetCM, entry := range uc.monitored.innerMap {
     1981                if _, ok := seen[targetCM]; ok {
     1982                        removeAll = false
     1983                } else {
     1984                        removeList = append(removeList, entry.originalKey)
     1985                }
     1986        }
     1987
     1988        // TODO: better handle the case where len(uc.monitored) + len(addList)
     1989        // exceeds the limit, probably by immediately sending ERR_MONLISTFULL?
     1990
     1991        if removeAll && len(addList) == 0 && len(removeList) > 0 {
     1992                // Optimization when the last MONITOR-aware downstream disconnects
     1993                uc.SendMessage(&irc.Message{
     1994                        Command: "MONITOR",
     1995                        Params:  []string{"C"},
     1996                })
     1997        } else {
     1998                msgs := generateMonitor("-", removeList)
     1999                msgs = append(msgs, generateMonitor("+", addList)...)
     2000                for _, msg := range msgs {
     2001                        uc.SendMessage(msg)
     2002                }
     2003        }
     2004
     2005        for _, target := range removeList {
     2006                uc.monitored.Delete(target)
     2007        }
     2008}
Note: See TracChangeset for help on using the changeset viewer.