3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 18:52:41 +01:00

channel: RWMutex for members access

This commit is contained in:
Daniel Oaks 2017-01-11 02:09:08 +10:00
parent efb3000717
commit 6f7c683247
5 changed files with 69 additions and 0 deletions

View File

@ -11,6 +11,8 @@ import (
"strconv"
"time"
"sync"
"github.com/DanielOaks/girc-go/ircmsg"
)
@ -18,6 +20,7 @@ type Channel struct {
flags ChannelModeSet
lists map[ChannelMode]*UserMaskSet
key string
membersMutex sync.RWMutex
members MemberSet
name string
nameCasefolded string
@ -63,6 +66,8 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel {
}
func (channel *Channel) IsEmpty() bool {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
return len(channel.members) == 0
}
@ -93,6 +98,9 @@ func (channel *Channel) Names(client *Client) {
// ClientIsAtLeast returns whether the client has at least the given channel privilege.
func (channel *Channel) ClientIsAtLeast(client *Client, permission ChannelMode) bool {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
// get voice, since it's not a part of ChannelPrivModes
if channel.members.HasMode(client, permission) {
return true
@ -134,6 +142,9 @@ func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string {
}
func (channel *Channel) Nicks(target *Client) []string {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
nicks := make([]string, len(channel.members))
@ -160,7 +171,9 @@ func (channel *Channel) Nick() string {
// <mode> <mode params>
func (channel *Channel) ModeString(client *Client) (str string) {
channel.membersMutex.RLock()
isMember := client.flags[Operator] || channel.members.Has(client)
channel.membersMutex.RUnlock()
showKey := isMember && (channel.key != "")
showUserLimit := channel.userLimit > 0
@ -192,6 +205,9 @@ func (channel *Channel) ModeString(client *Client) (str string) {
}
func (channel *Channel) IsFull() bool {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
return (channel.userLimit > 0) &&
(uint64(len(channel.members)) >= channel.userLimit)
}
@ -201,6 +217,9 @@ func (channel *Channel) CheckKey(key string) bool {
}
func (channel *Channel) Join(client *Client, key string) {
channel.membersMutex.Lock()
defer channel.membersMutex.Unlock()
if channel.members.Has(client) {
// already joined, no message?
return
@ -256,6 +275,9 @@ func (channel *Channel) Join(client *Client, key string) {
}
func (channel *Channel) Part(client *Client, message string) {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
if !channel.members.Has(client) {
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
return
@ -268,6 +290,9 @@ func (channel *Channel) Part(client *Client, message string) {
}
func (channel *Channel) GetTopic(client *Client) {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
if !channel.members.Has(client) {
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
return
@ -283,6 +308,9 @@ func (channel *Channel) GetTopic(client *Client) {
}
func (channel *Channel) SetTopic(client *Client, topic string) {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
if !(client.flags[Operator] || channel.members.Has(client)) {
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
return
@ -307,6 +335,9 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
}
func (channel *Channel) CanSpeak(client *Client) bool {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
if client.flags[Operator] {
return true
}
@ -335,6 +366,10 @@ func (channel *Channel) sendMessage(cmd string, minPrefix *ChannelMode, clientOn
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
return
}
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
// for STATUSMSG
var minPrefixMode ChannelMode
if minPrefix != nil {
@ -383,6 +418,9 @@ func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
op ModeOp, nick string) *ChannelModeChange {
channel.membersMutex.Lock()
defer channel.membersMutex.Unlock()
if nick == "" {
//TODO(dan): shouldn't this be handled before it reaches this function?
client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
@ -466,6 +504,9 @@ func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeO
}
func (channel *Channel) Quit(client *Client) {
channel.membersMutex.Lock()
defer channel.membersMutex.Unlock()
channel.members.Remove(client)
client.channels.Remove(channel)
@ -475,6 +516,9 @@ func (channel *Channel) Quit(client *Client) {
}
func (channel *Channel) Kick(client *Client, target *Client, comment string) {
channel.membersMutex.Lock()
defer channel.membersMutex.Unlock()
if !(client.flags[Operator] || channel.members.Has(client)) {
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
return
@ -504,6 +548,9 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
return
}
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
if !channel.members.Has(inviter) {
inviter.Send(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
return

View File

@ -308,6 +308,8 @@ func (client *Client) Friends(Capabilities ...Capability) ClientSet {
}
for channel := range client.channels {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
for member := range channel.members {
// make sure they have all the required caps
for _, Cap := range Capabilities {

View File

@ -345,6 +345,9 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
channelName, err := CasefoldChannel(msg.Params[0])
channel := server.channels.Get(channelName)
channel.membersMutex.Lock()
defer channel.membersMutex.Unlock()
if err != nil || channel == nil {
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
return false

View File

@ -87,12 +87,14 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
return
}
channel.membersMutex.RLock()
for member := range channel.members {
if member == client && !client.capabilities[EchoMessage] {
continue
}
member.Send(nil, source, "PRIVMSG", channel.name, message)
}
channel.membersMutex.RUnlock()
} else {
target, err := CasefoldName(targetString)
user := server.clients.Get(target)

View File

@ -843,6 +843,9 @@ func (client *Client) WhoisChannelsNames(target *Client) []string {
var chstrs []string
index := 0
for channel := range client.channels {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
// channel is secret and the target can't see it
if !target.flags[Operator] && channel.flags[Secret] && !channel.members.Has(target) {
continue
@ -933,6 +936,9 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
}
if channel != nil {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
flags += channel.members[client].Prefixes(target.capabilities[MultiPrefix])
channelName = channel.name
}
@ -940,6 +946,9 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
}
func whoChannel(client *Client, channel *Channel, friends ClientSet) {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
for member := range channel.members {
if !client.flags[Invisible] || friends[client] {
client.RplWhoReply(channel, member)
@ -1372,6 +1381,9 @@ func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
// make sure client has privs to kick the given user
//TODO(dan): split this into a separate function that checks if users have privs
// over other users, useful for things like -aoh as well
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
var hasPrivs bool
for _, mode := range ChannelPrivModes {
if channel.members[client][mode] {
@ -1448,6 +1460,9 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
}
func (target *Client) RplList(channel *Channel) {
channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock()
// get the correct number of channel members
var memberCount int
if target.flags[Operator] || channel.members.Has(target) {