Changeset 681 in code for trunk/upstream.go


Ignore:
Timestamp:
Nov 9, 2021, 8:32:26 PM (4 years ago)
Author:
contact
Message:

Remove support for mixed multi-upstream LIST

Multi-upstream connections can still send LIST commands with a
network suffix.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/upstream.go

    r674 r681  
    7373}
    7474
     75type pendingUpstreamCommand struct {
     76        downstreamID uint64
     77        cmd          *irc.Message
     78}
     79
    7580type upstreamConn struct {
    7681        conn
     
    105110        casemapIsSet bool
    106111
    107         // set of LIST commands in progress, per downstream
    108         pendingLISTDownstreamSet map[uint64]struct{}
     112        // Queue of LIST commands in progress. The first entry has been sent to the
     113        // server and is awaiting reply. The following entries have not been sent
     114        // yet.
     115        pendingLIST []pendingUpstreamCommand
    109116
    110117        gotMotd bool
     
    191198
    192199        uc := &upstreamConn{
    193                 conn:                     *newConn(network.user.srv, newNetIRCConn(netConn), &options),
    194                 network:                  network,
    195                 user:                     network.user,
    196                 channels:                 upstreamChannelCasemapMap{newCasemapMap(0)},
    197                 supportedCaps:            make(map[string]string),
    198                 caps:                     make(map[string]bool),
    199                 batches:                  make(map[string]batch),
    200                 availableChannelTypes:    stdChannelTypes,
    201                 availableChannelModes:    stdChannelModes,
    202                 availableMemberships:     stdMemberships,
    203                 isupport:                 make(map[string]*string),
    204                 pendingLISTDownstreamSet: make(map[uint64]struct{}),
     200                conn:                  *newConn(network.user.srv, newNetIRCConn(netConn), &options),
     201                network:               network,
     202                user:                  network.user,
     203                channels:              upstreamChannelCasemapMap{newCasemapMap(0)},
     204                supportedCaps:         make(map[string]string),
     205                caps:                  make(map[string]bool),
     206                batches:               make(map[string]batch),
     207                availableChannelTypes: stdChannelTypes,
     208                availableChannelModes: stdChannelModes,
     209                availableMemberships:  stdMemberships,
     210                isupport:              make(map[string]*string),
    205211        }
    206212        return uc, nil
     
    236242}
    237243
    238 func (uc *upstreamConn) getPendingLIST() *pendingLIST {
    239         for _, pl := range uc.user.pendingLISTs {
    240                 if _, ok := pl.pendingCommands[uc.network.ID]; !ok {
    241                         continue
    242                 }
    243                 return &pl
    244         }
    245         return nil
    246 }
    247 
    248 func (uc *upstreamConn) endPendingLISTs(all bool) (found bool) {
    249         found = false
    250         for i := 0; i < len(uc.user.pendingLISTs); i++ {
    251                 pl := uc.user.pendingLISTs[i]
    252                 if _, ok := pl.pendingCommands[uc.network.ID]; !ok {
    253                         continue
    254                 }
    255                 delete(pl.pendingCommands, uc.network.ID)
    256                 if len(pl.pendingCommands) == 0 {
    257                         uc.user.pendingLISTs = append(uc.user.pendingLISTs[:i], uc.user.pendingLISTs[i+1:]...)
    258                         i--
    259                         uc.forEachDownstreamByID(pl.downstreamID, func(dc *downstreamConn) {
    260                                 dc.SendMessage(&irc.Message{
    261                                         Prefix:  dc.srv.prefix(),
    262                                         Command: irc.RPL_LISTEND,
    263                                         Params:  []string{dc.nick, "End of /LIST"},
    264                                 })
    265                         })
    266                 }
    267                 found = true
    268                 if !all {
    269                         delete(uc.pendingLISTDownstreamSet, pl.downstreamID)
    270                         uc.user.forEachUpstream(func(uc *upstreamConn) {
    271                                 uc.trySendLIST(pl.downstreamID)
    272                         })
    273                         return
    274                 }
    275         }
    276         return
    277 }
    278 
    279 func (uc *upstreamConn) trySendLIST(downstreamID uint64) {
    280         if _, ok := uc.pendingLISTDownstreamSet[downstreamID]; ok {
    281                 // a LIST command is already pending
    282                 // we will try again when that command is completed
     244func (uc *upstreamConn) endPendingLISTs() {
     245        for _, pendingCmd := range uc.pendingLIST {
     246                uc.forEachDownstreamByID(pendingCmd.downstreamID, func(dc *downstreamConn) {
     247                        dc.SendMessage(&irc.Message{
     248                                Prefix:  dc.srv.prefix(),
     249                                Command: irc.RPL_LISTEND,
     250                                Params:  []string{dc.nick, "End of /LIST"},
     251                        })
     252                })
     253        }
     254        uc.pendingLIST = nil
     255}
     256
     257func (uc *upstreamConn) sendNextPendingLIST() {
     258        if len(uc.pendingLIST) == 0 {
    283259                return
    284260        }
    285 
    286         for _, pl := range uc.user.pendingLISTs {
    287                 if pl.downstreamID != downstreamID {
    288                         continue
    289                 }
    290                 // this is the first pending LIST command list of the downstream
    291                 listCommand, ok := pl.pendingCommands[uc.network.ID]
    292                 if !ok {
    293                         // there is no command for this upstream in these LIST commands
    294                         // do not send anything
    295                         continue
    296                 }
    297                 // there is a command for this upstream in these LIST commands
    298                 // send it now
    299 
    300                 uc.SendMessageLabeled(downstreamID, listCommand)
    301 
    302                 uc.pendingLISTDownstreamSet[downstreamID] = struct{}{}
    303                 return
    304         }
     261        uc.SendMessage(uc.pendingLIST[0].cmd)
     262}
     263
     264func (uc *upstreamConn) enqueueLIST(dc *downstreamConn, cmd *irc.Message) {
     265        uc.pendingLIST = append(uc.pendingLIST, pendingUpstreamCommand{
     266                downstreamID: dc.id,
     267                cmd:          cmd,
     268        })
     269
     270        if len(uc.pendingLIST) == 1 {
     271                uc.sendNextPendingLIST()
     272        }
     273}
     274
     275func (uc *upstreamConn) currentPendingLIST() (*downstreamConn, *irc.Message) {
     276        if len(uc.pendingLIST) == 0 {
     277                return nil, nil
     278        }
     279
     280        pendingCmd := uc.pendingLIST[0]
     281        for _, dc := range uc.user.downstreamConns {
     282                if dc.id == pendingCmd.downstreamID {
     283                        return dc, pendingCmd.cmd
     284                }
     285        }
     286
     287        return nil, pendingCmd.cmd
     288}
     289
     290func (uc *upstreamConn) dequeueLIST() (*downstreamConn, *irc.Message) {
     291        dc, cmd := uc.currentPendingLIST()
     292
     293        if len(uc.pendingLIST) > 0 {
     294                copy(uc.pendingLIST, uc.pendingLIST[1:])
     295                uc.pendingLIST = uc.pendingLIST[:len(uc.pendingLIST)-1]
     296        }
     297
     298        uc.sendNextPendingLIST()
     299
     300        return dc, cmd
    305301}
    306302
     
    11001096                }
    11011097
    1102                 pl := uc.getPendingLIST()
    1103                 if pl == nil {
     1098                dc, cmd := uc.currentPendingLIST()
     1099                if cmd == nil {
    11041100                        return fmt.Errorf("unexpected RPL_LIST: no matching pending LIST")
    1105                 }
    1106 
    1107                 uc.forEachDownstreamByID(pl.downstreamID, func(dc *downstreamConn) {
    1108                         dc.SendMessage(&irc.Message{
    1109                                 Prefix:  dc.srv.prefix(),
    1110                                 Command: irc.RPL_LIST,
    1111                                 Params:  []string{dc.nick, dc.marshalEntity(uc.network, channel), clients, topic},
    1112                         })
     1101                } else if dc == nil {
     1102                        return nil
     1103                }
     1104
     1105                dc.SendMessage(&irc.Message{
     1106                        Prefix:  dc.srv.prefix(),
     1107                        Command: irc.RPL_LIST,
     1108                        Params:  []string{dc.nick, dc.marshalEntity(uc.network, channel), clients, topic},
    11131109                })
    11141110        case irc.RPL_LISTEND:
    1115                 ok := uc.endPendingLISTs(false)
    1116                 if !ok {
     1111                dc, cmd := uc.dequeueLIST()
     1112                if cmd == nil {
    11171113                        return fmt.Errorf("unexpected RPL_LISTEND: no matching pending LIST")
    1118                 }
     1114                } else if dc == nil {
     1115                        return nil
     1116                }
     1117
     1118                dc.SendMessage(&irc.Message{
     1119                        Prefix:  dc.srv.prefix(),
     1120                        Command: irc.RPL_LISTEND,
     1121                        Params:  []string{dc.nick, "End of /LIST"},
     1122                })
    11191123        case irc.RPL_NAMREPLY:
    11201124                var name, statusStr, members string
     
    14341438
    14351439                if command == "LIST" {
    1436                         ok := uc.endPendingLISTs(false)
    1437                         if !ok {
    1438                                 return fmt.Errorf("unexpected response for LIST: %q: no matching pending LIST", msg.Command)
    1439                         }
     1440                        uc.endPendingLISTs()
    14401441                }
    14411442
Note: See TracChangeset for help on using the changeset viewer.