mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-25 21:39:25 +01:00
fix #1507
Registered channels should be eagerly created on startup, and should remain (and be visible in LIST) even when they have no members.
This commit is contained in:
parent
1fad76b906
commit
cc6be14c1d
@ -210,8 +210,6 @@ func (channel *Channel) MarkDirty(dirtyBits uint) {
|
|||||||
// ChannelManager's lock (that way, no one can join and make the channel dirty again
|
// ChannelManager's lock (that way, no one can join and make the channel dirty again
|
||||||
// between this method exiting and the actual deletion).
|
// between this method exiting and the actual deletion).
|
||||||
func (channel *Channel) IsClean() bool {
|
func (channel *Channel) IsClean() bool {
|
||||||
config := channel.server.Config()
|
|
||||||
|
|
||||||
if !channel.writerSemaphore.TryAcquire() {
|
if !channel.writerSemaphore.TryAcquire() {
|
||||||
// a database write (which may fail) is in progress, the channel cannot be cleaned up
|
// a database write (which may fail) is in progress, the channel cannot be cleaned up
|
||||||
return false
|
return false
|
||||||
@ -223,13 +221,8 @@ func (channel *Channel) IsClean() bool {
|
|||||||
if len(channel.members) != 0 {
|
if len(channel.members) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if channel.registeredFounder == "" {
|
// see #1507 and #704 among others; registered channels should never be removed
|
||||||
return true
|
return channel.registeredFounder == ""
|
||||||
}
|
|
||||||
// a registered channel must be fully written to the DB,
|
|
||||||
// and not set to ephemeral history (#704)
|
|
||||||
return channel.dirtyBits == 0 &&
|
|
||||||
channelHistoryStatus(config, true, channel.settings.History) != HistoryEphemeral
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) wakeWriter() {
|
func (channel *Channel) wakeWriter() {
|
||||||
@ -793,7 +786,7 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
|
|||||||
return joinErr, ""
|
return joinErr, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
client.server.logger.Debug("join", fmt.Sprintf("%s joined channel %s", details.nick, chname))
|
client.server.logger.Debug("channels", fmt.Sprintf("%s joined channel %s", details.nick, chname))
|
||||||
|
|
||||||
givenMode := func() (givenMode modes.Mode) {
|
givenMode := func() (givenMode modes.Mode) {
|
||||||
channel.joinPartMutex.Lock()
|
channel.joinPartMutex.Lock()
|
||||||
@ -1033,7 +1026,7 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
|
|||||||
}, details.account)
|
}, details.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
client.server.logger.Debug("part", fmt.Sprintf("%s left channel %s", details.nick, chname))
|
client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resume is called after a successful global resume to:
|
// Resume is called after a successful global resume to:
|
||||||
@ -1539,6 +1532,32 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string, rb
|
|||||||
channel.Quit(target)
|
channel.Quit(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle a purge: kick everyone off the channel, clean up all the pointers between
|
||||||
|
// *Channel and *Client
|
||||||
|
func (channel *Channel) Purge(source string) {
|
||||||
|
if source == "" {
|
||||||
|
source = channel.server.name
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.stateMutex.Lock()
|
||||||
|
chname := channel.name
|
||||||
|
members := channel.membersCache
|
||||||
|
channel.membersCache = nil
|
||||||
|
channel.members = make(MemberSet)
|
||||||
|
// TODO try to prevent Purge racing against (pending) Join?
|
||||||
|
channel.stateMutex.Unlock()
|
||||||
|
|
||||||
|
now := time.Now().UTC()
|
||||||
|
for _, member := range members {
|
||||||
|
tnick := member.Nick()
|
||||||
|
msgid := utils.GenerateSecretToken()
|
||||||
|
for _, session := range member.Sessions() {
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
member.removeChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Invite invites the given client to the channel, if the inviter can do so.
|
// Invite invites the given client to the channel, if the inviter can do so.
|
||||||
func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
|
func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuffer) {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
|
@ -39,9 +39,9 @@ func (cm *ChannelManager) Initialize(server *Server) {
|
|||||||
cm.chansSkeletons = make(utils.StringSet)
|
cm.chansSkeletons = make(utils.StringSet)
|
||||||
cm.server = server
|
cm.server = server
|
||||||
|
|
||||||
cm.loadRegisteredChannels(server.Config())
|
|
||||||
// purging should work even if registration is disabled
|
// purging should work even if registration is disabled
|
||||||
cm.purgedChannels = cm.server.channelRegistry.PurgedChannels()
|
cm.purgedChannels = cm.server.channelRegistry.PurgedChannels()
|
||||||
|
cm.loadRegisteredChannels(server.Config())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
|
func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
|
||||||
@ -49,23 +49,48 @@ func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var newChannels []*Channel
|
||||||
|
var collisions []string
|
||||||
|
defer func() {
|
||||||
|
for _, ch := range newChannels {
|
||||||
|
ch.EnsureLoaded()
|
||||||
|
cm.server.logger.Debug("channels", "initialized registered channel", ch.Name())
|
||||||
|
}
|
||||||
|
for _, collision := range collisions {
|
||||||
|
cm.server.logger.Warning("channels", "registered channel collides with existing channel", collision)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
rawNames := cm.server.channelRegistry.AllChannels()
|
rawNames := cm.server.channelRegistry.AllChannels()
|
||||||
registeredChannels := make(utils.StringSet, len(rawNames))
|
|
||||||
registeredSkeletons := make(utils.StringSet, len(rawNames))
|
cm.Lock()
|
||||||
|
defer cm.Unlock()
|
||||||
|
|
||||||
|
cm.registeredChannels = make(utils.StringSet, len(rawNames))
|
||||||
|
cm.registeredSkeletons = make(utils.StringSet, len(rawNames))
|
||||||
for _, name := range rawNames {
|
for _, name := range rawNames {
|
||||||
cfname, err := CasefoldChannel(name)
|
cfname, err := CasefoldChannel(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
registeredChannels.Add(cfname)
|
cm.registeredChannels.Add(cfname)
|
||||||
}
|
}
|
||||||
skeleton, err := Skeleton(name)
|
skeleton, err := Skeleton(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
registeredSkeletons.Add(skeleton)
|
cm.registeredSkeletons.Add(skeleton)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cm.purgedChannels.Has(cfname) {
|
||||||
|
if _, ok := cm.chans[cfname]; !ok {
|
||||||
|
ch := NewChannel(cm.server, name, cfname, true)
|
||||||
|
cm.chans[cfname] = &channelManagerEntry{
|
||||||
|
channel: ch,
|
||||||
|
pendingJoins: 0,
|
||||||
|
}
|
||||||
|
newChannels = append(newChannels, ch)
|
||||||
|
} else {
|
||||||
|
collisions = append(collisions, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cm.Lock()
|
|
||||||
defer cm.Unlock()
|
|
||||||
cm.registeredChannels = registeredChannels
|
|
||||||
cm.registeredSkeletons = registeredSkeletons
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns an existing channel with name equivalent to `name`, or nil
|
// Get returns an existing channel with name equivalent to `name`, or nil
|
||||||
@ -366,12 +391,28 @@ func (cm *ChannelManager) Purge(chname string, record ChannelPurgeRecord) (err e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errInvalidChannelName
|
return errInvalidChannelName
|
||||||
}
|
}
|
||||||
|
skel, err := Skeleton(chname)
|
||||||
|
if err != nil {
|
||||||
|
return errInvalidChannelName
|
||||||
|
}
|
||||||
|
|
||||||
cm.Lock()
|
cm.Lock()
|
||||||
cm.purgedChannels.Add(chname)
|
cm.purgedChannels.Add(chname)
|
||||||
|
entry := cm.chans[chname]
|
||||||
|
if entry != nil {
|
||||||
|
delete(cm.chans, chname)
|
||||||
|
if entry.channel.Founder() != "" {
|
||||||
|
delete(cm.registeredSkeletons, skel)
|
||||||
|
} else {
|
||||||
|
delete(cm.chansSkeletons, skel)
|
||||||
|
}
|
||||||
|
}
|
||||||
cm.Unlock()
|
cm.Unlock()
|
||||||
|
|
||||||
cm.server.channelRegistry.PurgeChannel(chname, record)
|
cm.server.channelRegistry.PurgeChannel(chname, record)
|
||||||
|
if entry != nil {
|
||||||
|
entry.channel.Purge("")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1614,9 +1614,8 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
|
|||||||
|
|
||||||
nick := client.Nick()
|
nick := client.Nick()
|
||||||
rplList := func(channel *Channel) {
|
rplList := func(channel *Channel) {
|
||||||
if members, name, topic := channel.listData(); members != 0 {
|
members, name, topic := channel.listData()
|
||||||
rb.Add(nil, client.server.name, RPL_LIST, nick, name, strconv.Itoa(members), topic)
|
rb.Add(nil, client.server.name, RPL_LIST, nick, name, strconv.Itoa(members), topic)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clientIsOp := client.HasMode(modes.Operator)
|
clientIsOp := client.HasMode(modes.Operator)
|
||||||
|
Loading…
Reference in New Issue
Block a user