Changeset 681 in code for trunk/upstream.go
- Timestamp:
- Nov 9, 2021, 8:32:26 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/upstream.go
r674 r681 73 73 } 74 74 75 type pendingUpstreamCommand struct { 76 downstreamID uint64 77 cmd *irc.Message 78 } 79 75 80 type upstreamConn struct { 76 81 conn … … 105 110 casemapIsSet bool 106 111 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 109 116 110 117 gotMotd bool … … 191 198 192 199 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), 205 211 } 206 212 return uc, nil … … 236 242 } 237 243 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 244 func (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 257 func (uc *upstreamConn) sendNextPendingLIST() { 258 if len(uc.pendingLIST) == 0 { 283 259 return 284 260 } 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 264 func (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 275 func (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 290 func (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 305 301 } 306 302 … … 1100 1096 } 1101 1097 1102 pl := uc.getPendingLIST()1103 if pl== nil {1098 dc, cmd := uc.currentPendingLIST() 1099 if cmd == nil { 1104 1100 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}, 1113 1109 }) 1114 1110 case irc.RPL_LISTEND: 1115 ok := uc.endPendingLISTs(false)1116 if !ok{1111 dc, cmd := uc.dequeueLIST() 1112 if cmd == nil { 1117 1113 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 }) 1119 1123 case irc.RPL_NAMREPLY: 1120 1124 var name, statusStr, members string … … 1434 1438 1435 1439 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() 1440 1441 } 1441 1442
Note:
See TracChangeset
for help on using the changeset viewer.