소스 검색

fix #1507

Registered channels should be eagerly created on startup, and should
remain (and be visible in LIST) even when they have no members.
tags/v2.6.0-rc1
Shivaram Lingamneni 3 년 전
부모
커밋
cc6be14c1d
3개의 변경된 파일82개의 추가작업 그리고 23개의 파일을 삭제
  1. 30
    11
      irc/channel.go
  2. 50
    9
      irc/channelmanager.go
  3. 2
    3
      irc/handlers.go

+ 30
- 11
irc/channel.go 파일 보기

210
 // ChannelManager's lock (that way, no one can join and make the channel dirty again
210
 // ChannelManager's lock (that way, no one can join and make the channel dirty again
211
 // between this method exiting and the actual deletion).
211
 // between this method exiting and the actual deletion).
212
 func (channel *Channel) IsClean() bool {
212
 func (channel *Channel) IsClean() bool {
213
-	config := channel.server.Config()
214
-
215
 	if !channel.writerSemaphore.TryAcquire() {
213
 	if !channel.writerSemaphore.TryAcquire() {
216
 		// a database write (which may fail) is in progress, the channel cannot be cleaned up
214
 		// a database write (which may fail) is in progress, the channel cannot be cleaned up
217
 		return false
215
 		return false
223
 	if len(channel.members) != 0 {
221
 	if len(channel.members) != 0 {
224
 		return false
222
 		return false
225
 	}
223
 	}
226
-	if channel.registeredFounder == "" {
227
-		return true
228
-	}
229
-	// a registered channel must be fully written to the DB,
230
-	// and not set to ephemeral history (#704)
231
-	return channel.dirtyBits == 0 &&
232
-		channelHistoryStatus(config, true, channel.settings.History) != HistoryEphemeral
224
+	// see #1507 and #704 among others; registered channels should never be removed
225
+	return channel.registeredFounder == ""
233
 }
226
 }
234
 
227
 
235
 func (channel *Channel) wakeWriter() {
228
 func (channel *Channel) wakeWriter() {
793
 		return joinErr, ""
786
 		return joinErr, ""
794
 	}
787
 	}
795
 
788
 
796
-	client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", details.nick, chname))
789
+	client.server.logger.Debug("channels", fmt.Sprintf("%s joined channel %s", details.nick, chname))
797
 
790
 
798
 	givenMode := func() (givenMode modes.Mode) {
791
 	givenMode := func() (givenMode modes.Mode) {
799
 		channel.joinPartMutex.Lock()
792
 		channel.joinPartMutex.Lock()
1033
 		}, details.account)
1026
 		}, details.account)
1034
 	}
1027
 	}
1035
 
1028
 
1036
-	client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
1029
+	client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname))
1037
 }
1030
 }
1038
 
1031
 
1039
 // Resume is called after a successful global resume to:
1032
 // Resume is called after a successful global resume to:
1539
 	channel.Quit(target)
1532
 	channel.Quit(target)
1540
 }
1533
 }
1541
 
1534
 
1535
+// handle a purge: kick everyone off the channel, clean up all the pointers between
1536
+// *Channel and *Client
1537
+func (channel *Channel) Purge(source string) {
1538
+	if source == "" {
1539
+		source = channel.server.name
1540
+	}
1541
+
1542
+	channel.stateMutex.Lock()
1543
+	chname := channel.name
1544
+	members := channel.membersCache
1545
+	channel.membersCache = nil
1546
+	channel.members = make(MemberSet)
1547
+	// TODO try to prevent Purge racing against (pending) Join?
1548
+	channel.stateMutex.Unlock()
1549
+
1550
+	now := time.Now().UTC()
1551
+	for _, member := range members {
1552
+		tnick := member.Nick()
1553
+		msgid := utils.GenerateSecretToken()
1554
+		for _, session := range member.Sessions() {
1555
+			session.sendFromClientInternal(false, now, msgid, source, "*", nil, "KICK", chname, tnick, member.t("This channel has been purged by the server administrators and cannot be used"))
1556
+		}
1557
+		member.removeChannel(channel)
1558
+	}
1559
+}
1560
+
1542
 // Invite invites the given client to the channel, if the inviter can do so.
1561
 // Invite invites the given client to the channel, if the inviter can do so.
1543
 func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
1562
 func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
1544
 	channel.stateMutex.RLock()
1563
 	channel.stateMutex.RLock()

+ 50
- 9
irc/channelmanager.go 파일 보기

39
 	cm.chansSkeletons = make(utils.StringSet)
39
 	cm.chansSkeletons = make(utils.StringSet)
40
 	cm.server = server
40
 	cm.server = server
41
 
41
 
42
-	cm.loadRegisteredChannels(server.Config())
43
 	// purging should work even if registration is disabled
42
 	// purging should work even if registration is disabled
44
 	cm.purgedChannels = cm.server.channelRegistry.PurgedChannels()
43
 	cm.purgedChannels = cm.server.channelRegistry.PurgedChannels()
44
+	cm.loadRegisteredChannels(server.Config())
45
 }
45
 }
46
 
46
 
47
 func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
47
 func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
49
 		return
49
 		return
50
 	}
50
 	}
51
 
51
 
52
+	var newChannels []*Channel
53
+	var collisions []string
54
+	defer func() {
55
+		for _, ch := range newChannels {
56
+			ch.EnsureLoaded()
57
+			cm.server.logger.Debug("channels", "initialized registered channel", ch.Name())
58
+		}
59
+		for _, collision := range collisions {
60
+			cm.server.logger.Warning("channels", "registered channel collides with existing channel", collision)
61
+		}
62
+	}()
63
+
52
 	rawNames := cm.server.channelRegistry.AllChannels()
64
 	rawNames := cm.server.channelRegistry.AllChannels()
53
-	registeredChannels := make(utils.StringSet, len(rawNames))
54
-	registeredSkeletons := make(utils.StringSet, len(rawNames))
65
+
66
+	cm.Lock()
67
+	defer cm.Unlock()
68
+
69
+	cm.registeredChannels = make(utils.StringSet, len(rawNames))
70
+	cm.registeredSkeletons = make(utils.StringSet, len(rawNames))
55
 	for _, name := range rawNames {
71
 	for _, name := range rawNames {
56
 		cfname, err := CasefoldChannel(name)
72
 		cfname, err := CasefoldChannel(name)
57
 		if err == nil {
73
 		if err == nil {
58
-			registeredChannels.Add(cfname)
74
+			cm.registeredChannels.Add(cfname)
59
 		}
75
 		}
60
 		skeleton, err := Skeleton(name)
76
 		skeleton, err := Skeleton(name)
61
 		if err == nil {
77
 		if err == nil {
62
-			registeredSkeletons.Add(skeleton)
78
+			cm.registeredSkeletons.Add(skeleton)
79
+		}
80
+
81
+		if !cm.purgedChannels.Has(cfname) {
82
+			if _, ok := cm.chans[cfname]; !ok {
83
+				ch := NewChannel(cm.server, name, cfname, true)
84
+				cm.chans[cfname] = &channelManagerEntry{
85
+					channel:      ch,
86
+					pendingJoins: 0,
87
+				}
88
+				newChannels = append(newChannels, ch)
89
+			} else {
90
+				collisions = append(collisions, name)
91
+			}
63
 		}
92
 		}
64
 	}
93
 	}
65
-	cm.Lock()
66
-	defer cm.Unlock()
67
-	cm.registeredChannels = registeredChannels
68
-	cm.registeredSkeletons = registeredSkeletons
69
 }
94
 }
70
 
95
 
71
 // Get returns an existing channel with name equivalent to `name`, or nil
96
 // Get returns an existing channel with name equivalent to `name`, or nil
366
 	if err != nil {
391
 	if err != nil {
367
 		return errInvalidChannelName
392
 		return errInvalidChannelName
368
 	}
393
 	}
394
+	skel, err := Skeleton(chname)
395
+	if err != nil {
396
+		return errInvalidChannelName
397
+	}
369
 
398
 
370
 	cm.Lock()
399
 	cm.Lock()
371
 	cm.purgedChannels.Add(chname)
400
 	cm.purgedChannels.Add(chname)
401
+	entry := cm.chans[chname]
402
+	if entry != nil {
403
+		delete(cm.chans, chname)
404
+		if entry.channel.Founder() != "" {
405
+			delete(cm.registeredSkeletons, skel)
406
+		} else {
407
+			delete(cm.chansSkeletons, skel)
408
+		}
409
+	}
372
 	cm.Unlock()
410
 	cm.Unlock()
373
 
411
 
374
 	cm.server.channelRegistry.PurgeChannel(chname, record)
412
 	cm.server.channelRegistry.PurgeChannel(chname, record)
413
+	if entry != nil {
414
+		entry.channel.Purge("")
415
+	}
375
 	return nil
416
 	return nil
376
 }
417
 }
377
 
418
 

+ 2
- 3
irc/handlers.go 파일 보기

1614
 
1614
 
1615
 	nick := client.Nick()
1615
 	nick := client.Nick()
1616
 	rplList := func(channel *Channel) {
1616
 	rplList := func(channel *Channel) {
1617
-		if members, name, topic := channel.listData(); members != 0 {
1618
-			rb.Add(nil, client.server.name, RPL_LIST, nick, name, strconv.Itoa(members), topic)
1619
-		}
1617
+		members, name, topic := channel.listData()
1618
+		rb.Add(nil, client.server.name, RPL_LIST, nick, name, strconv.Itoa(members), topic)
1620
 	}
1619
 	}
1621
 
1620
 
1622
 	clientIsOp := client.HasMode(modes.Operator)
1621
 	clientIsOp := client.HasMode(modes.Operator)

Loading…
취소
저장