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:
parent
efb3000717
commit
6f7c683247
@ -11,6 +11,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/DanielOaks/girc-go/ircmsg"
|
"github.com/DanielOaks/girc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,6 +20,7 @@ type Channel struct {
|
|||||||
flags ChannelModeSet
|
flags ChannelModeSet
|
||||||
lists map[ChannelMode]*UserMaskSet
|
lists map[ChannelMode]*UserMaskSet
|
||||||
key string
|
key string
|
||||||
|
membersMutex sync.RWMutex
|
||||||
members MemberSet
|
members MemberSet
|
||||||
name string
|
name string
|
||||||
nameCasefolded string
|
nameCasefolded string
|
||||||
@ -63,6 +66,8 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) IsEmpty() bool {
|
func (channel *Channel) IsEmpty() bool {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
return len(channel.members) == 0
|
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.
|
// ClientIsAtLeast returns whether the client has at least the given channel privilege.
|
||||||
func (channel *Channel) ClientIsAtLeast(client *Client, permission ChannelMode) bool {
|
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
|
// get voice, since it's not a part of ChannelPrivModes
|
||||||
if channel.members.HasMode(client, permission) {
|
if channel.members.HasMode(client, permission) {
|
||||||
return true
|
return true
|
||||||
@ -134,6 +142,9 @@ func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) Nicks(target *Client) []string {
|
func (channel *Channel) Nicks(target *Client) []string {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
|
isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
|
||||||
isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
|
isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
|
||||||
nicks := make([]string, len(channel.members))
|
nicks := make([]string, len(channel.members))
|
||||||
@ -160,7 +171,9 @@ func (channel *Channel) Nick() string {
|
|||||||
|
|
||||||
// <mode> <mode params>
|
// <mode> <mode params>
|
||||||
func (channel *Channel) ModeString(client *Client) (str string) {
|
func (channel *Channel) ModeString(client *Client) (str string) {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
isMember := client.flags[Operator] || channel.members.Has(client)
|
isMember := client.flags[Operator] || channel.members.Has(client)
|
||||||
|
channel.membersMutex.RUnlock()
|
||||||
showKey := isMember && (channel.key != "")
|
showKey := isMember && (channel.key != "")
|
||||||
showUserLimit := channel.userLimit > 0
|
showUserLimit := channel.userLimit > 0
|
||||||
|
|
||||||
@ -192,6 +205,9 @@ func (channel *Channel) ModeString(client *Client) (str string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) IsFull() bool {
|
func (channel *Channel) IsFull() bool {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
return (channel.userLimit > 0) &&
|
return (channel.userLimit > 0) &&
|
||||||
(uint64(len(channel.members)) >= channel.userLimit)
|
(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) {
|
func (channel *Channel) Join(client *Client, key string) {
|
||||||
|
channel.membersMutex.Lock()
|
||||||
|
defer channel.membersMutex.Unlock()
|
||||||
|
|
||||||
if channel.members.Has(client) {
|
if channel.members.Has(client) {
|
||||||
// already joined, no message?
|
// already joined, no message?
|
||||||
return
|
return
|
||||||
@ -256,6 +275,9 @@ func (channel *Channel) Join(client *Client, key string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) Part(client *Client, message string) {
|
func (channel *Channel) Part(client *Client, message string) {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
if !channel.members.Has(client) {
|
if !channel.members.Has(client) {
|
||||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
||||||
return
|
return
|
||||||
@ -268,6 +290,9 @@ func (channel *Channel) Part(client *Client, message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) GetTopic(client *Client) {
|
func (channel *Channel) GetTopic(client *Client) {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
if !channel.members.Has(client) {
|
if !channel.members.Has(client) {
|
||||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
|
||||||
return
|
return
|
||||||
@ -283,6 +308,9 @@ func (channel *Channel) GetTopic(client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) SetTopic(client *Client, topic string) {
|
func (channel *Channel) SetTopic(client *Client, topic string) {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
if !(client.flags[Operator] || channel.members.Has(client)) {
|
if !(client.flags[Operator] || channel.members.Has(client)) {
|
||||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
||||||
return
|
return
|
||||||
@ -307,6 +335,9 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) CanSpeak(client *Client) bool {
|
func (channel *Channel) CanSpeak(client *Client) bool {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
if client.flags[Operator] {
|
if client.flags[Operator] {
|
||||||
return true
|
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")
|
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
// for STATUSMSG
|
// for STATUSMSG
|
||||||
var minPrefixMode ChannelMode
|
var minPrefixMode ChannelMode
|
||||||
if minPrefix != nil {
|
if minPrefix != nil {
|
||||||
@ -383,6 +418,9 @@ func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
|
|||||||
|
|
||||||
func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
|
func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
|
||||||
op ModeOp, nick string) *ChannelModeChange {
|
op ModeOp, nick string) *ChannelModeChange {
|
||||||
|
channel.membersMutex.Lock()
|
||||||
|
defer channel.membersMutex.Unlock()
|
||||||
|
|
||||||
if nick == "" {
|
if nick == "" {
|
||||||
//TODO(dan): shouldn't this be handled before it reaches this function?
|
//TODO(dan): shouldn't this be handled before it reaches this function?
|
||||||
client.Send(nil, client.server.name, ERR_NEEDMOREPARAMS, "MODE", "Not enough parameters")
|
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) {
|
func (channel *Channel) Quit(client *Client) {
|
||||||
|
channel.membersMutex.Lock()
|
||||||
|
defer channel.membersMutex.Unlock()
|
||||||
|
|
||||||
channel.members.Remove(client)
|
channel.members.Remove(client)
|
||||||
client.channels.Remove(channel)
|
client.channels.Remove(channel)
|
||||||
|
|
||||||
@ -475,6 +516,9 @@ func (channel *Channel) Quit(client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) Kick(client *Client, target *Client, comment string) {
|
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)) {
|
if !(client.flags[Operator] || channel.members.Has(client)) {
|
||||||
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
||||||
return
|
return
|
||||||
@ -504,6 +548,9 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
if !channel.members.Has(inviter) {
|
if !channel.members.Has(inviter) {
|
||||||
inviter.Send(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
inviter.Send(nil, inviter.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
|
||||||
return
|
return
|
||||||
|
@ -308,6 +308,8 @@ func (client *Client) Friends(Capabilities ...Capability) ClientSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for channel := range client.channels {
|
for channel := range client.channels {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
// make sure they have all the required caps
|
// make sure they have all the required caps
|
||||||
for _, Cap := range Capabilities {
|
for _, Cap := range Capabilities {
|
||||||
|
@ -345,6 +345,9 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|||||||
channelName, err := CasefoldChannel(msg.Params[0])
|
channelName, err := CasefoldChannel(msg.Params[0])
|
||||||
channel := server.channels.Get(channelName)
|
channel := server.channels.Get(channelName)
|
||||||
|
|
||||||
|
channel.membersMutex.Lock()
|
||||||
|
defer channel.membersMutex.Unlock()
|
||||||
|
|
||||||
if err != nil || channel == nil {
|
if err != nil || channel == nil {
|
||||||
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
|
client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
|
||||||
return false
|
return false
|
||||||
|
@ -87,12 +87,14 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel.membersMutex.RLock()
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
if member == client && !client.capabilities[EchoMessage] {
|
if member == client && !client.capabilities[EchoMessage] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
member.Send(nil, source, "PRIVMSG", channel.name, message)
|
member.Send(nil, source, "PRIVMSG", channel.name, message)
|
||||||
}
|
}
|
||||||
|
channel.membersMutex.RUnlock()
|
||||||
} else {
|
} else {
|
||||||
target, err := CasefoldName(targetString)
|
target, err := CasefoldName(targetString)
|
||||||
user := server.clients.Get(target)
|
user := server.clients.Get(target)
|
||||||
|
@ -843,6 +843,9 @@ func (client *Client) WhoisChannelsNames(target *Client) []string {
|
|||||||
var chstrs []string
|
var chstrs []string
|
||||||
index := 0
|
index := 0
|
||||||
for channel := range client.channels {
|
for channel := range client.channels {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
// channel is secret and the target can't see it
|
// channel is secret and the target can't see it
|
||||||
if !target.flags[Operator] && channel.flags[Secret] && !channel.members.Has(target) {
|
if !target.flags[Operator] && channel.flags[Secret] && !channel.members.Has(target) {
|
||||||
continue
|
continue
|
||||||
@ -933,6 +936,9 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if channel != nil {
|
if channel != nil {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
flags += channel.members[client].Prefixes(target.capabilities[MultiPrefix])
|
flags += channel.members[client].Prefixes(target.capabilities[MultiPrefix])
|
||||||
channelName = channel.name
|
channelName = channel.name
|
||||||
}
|
}
|
||||||
@ -940,6 +946,9 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func whoChannel(client *Client, channel *Channel, friends ClientSet) {
|
func whoChannel(client *Client, channel *Channel, friends ClientSet) {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
if !client.flags[Invisible] || friends[client] {
|
if !client.flags[Invisible] || friends[client] {
|
||||||
client.RplWhoReply(channel, member)
|
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
|
// make sure client has privs to kick the given user
|
||||||
//TODO(dan): split this into a separate function that checks if users have privs
|
//TODO(dan): split this into a separate function that checks if users have privs
|
||||||
// over other users, useful for things like -aoh as well
|
// over other users, useful for things like -aoh as well
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
var hasPrivs bool
|
var hasPrivs bool
|
||||||
for _, mode := range ChannelPrivModes {
|
for _, mode := range ChannelPrivModes {
|
||||||
if channel.members[client][mode] {
|
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) {
|
func (target *Client) RplList(channel *Channel) {
|
||||||
|
channel.membersMutex.RLock()
|
||||||
|
defer channel.membersMutex.RUnlock()
|
||||||
|
|
||||||
// get the correct number of channel members
|
// get the correct number of channel members
|
||||||
var memberCount int
|
var memberCount int
|
||||||
if target.flags[Operator] || channel.members.Has(target) {
|
if target.flags[Operator] || channel.members.Has(target) {
|
||||||
|
Loading…
Reference in New Issue
Block a user