mirror of
https://github.com/ergochat/ergo.git
synced 2025-12-20 02:00:11 -08:00
refactor update broadcast
This commit is contained in:
parent
e6aaaf1b88
commit
3966c17dec
3 changed files with 42 additions and 26 deletions
|
|
@ -7,6 +7,7 @@ package irc
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"iter"
|
||||
"maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -1676,6 +1677,20 @@ func (channel *Channel) auditoriumFriends(client *Client) (friends []*Client) {
|
|||
return
|
||||
}
|
||||
|
||||
func (channel *Channel) sessionsWithCap(capabs ...caps.Capability) iter.Seq[*Session] {
|
||||
return func(yield func(*Session) bool) {
|
||||
for _, member := range channel.Members() {
|
||||
for _, sess := range member.Sessions() {
|
||||
if sess.capabilities.HasAll(capabs...) {
|
||||
if !yield(sess) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns whether the client is visible to unprivileged users in the channel
|
||||
// (i.e., respecting auditorium mode). note that this assumes that the client
|
||||
// is a member; if the client is not, it may return true anyway
|
||||
|
|
|
|||
|
|
@ -3129,11 +3129,13 @@ func metadataHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
|
|||
targetChannel = server.channels.Get(target)
|
||||
if targetChannel != nil {
|
||||
targetObj = targetChannel
|
||||
target = targetChannel.Name() // canonicalize case
|
||||
}
|
||||
} else {
|
||||
targetClient = server.clients.Get(target)
|
||||
if targetClient != nil {
|
||||
targetObj = targetClient
|
||||
target = targetClient.Nick() // canonicalize case
|
||||
}
|
||||
}
|
||||
if targetObj == nil {
|
||||
|
|
@ -3180,13 +3182,14 @@ func metadataHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
|
|||
server.logger.Debug("metadata", "setting", key, value, "on", target)
|
||||
|
||||
targetObj.SetMetadata(key, value)
|
||||
notifySubscribers(server, rb.session, target, key, value)
|
||||
notifySubscribers(server, rb.session, targetObj, target, key, value)
|
||||
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, client.Nick(), originalTarget, key, "*", value)
|
||||
} else {
|
||||
server.logger.Debug("metadata", "deleting", key, "on", target)
|
||||
// TODO check success or failure here
|
||||
targetObj.DeleteMetadata(key)
|
||||
notifySubscribers(server, rb.session, target, key, "")
|
||||
notifySubscribers(server, rb.session, targetObj, target, key, "")
|
||||
|
||||
rb.Add(nil, server.name, RPL_KEYNOTSET, client.Nick(), target, key, client.t("Key deleted"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@ package irc
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"iter"
|
||||
"maps"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ergochat/ergo/irc/caps"
|
||||
"github.com/ergochat/ergo/irc/modes"
|
||||
"github.com/ergochat/ergo/irc/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -24,34 +25,31 @@ type MetadataHaver = interface {
|
|||
CountMetadata() int
|
||||
}
|
||||
|
||||
func notifySubscribers(server *Server, session *Session, target string, key string, value string) {
|
||||
var notify utils.HashSet[*Session] = make(utils.HashSet[*Session])
|
||||
targetChannel := server.channels.Get(target)
|
||||
targetClient := server.clients.Get(target)
|
||||
func notifySubscribers(server *Server, session *Session, targetObj MetadataHaver, targetName, key, value string) {
|
||||
var recipientSessions iter.Seq[*Session]
|
||||
|
||||
if targetClient != nil {
|
||||
notify = targetClient.FriendsMonitors(caps.Metadata)
|
||||
// notify clients about changes regarding themselves
|
||||
for _, s := range targetClient.Sessions() {
|
||||
notify.Add(s)
|
||||
}
|
||||
}
|
||||
if targetChannel != nil {
|
||||
members := targetChannel.Members()
|
||||
for _, m := range members {
|
||||
for _, s := range m.Sessions() {
|
||||
if s.capabilities.Has(caps.Metadata) {
|
||||
notify.Add(s)
|
||||
}
|
||||
}
|
||||
switch target := targetObj.(type) {
|
||||
case *Client:
|
||||
// TODO this case is expensive and might warrant rate-limiting
|
||||
friends := target.FriendsMonitors(caps.Metadata)
|
||||
// broadcast metadata update to other connected sessions
|
||||
for _, s := range target.Sessions() {
|
||||
friends.Add(s)
|
||||
}
|
||||
recipientSessions = maps.Keys(friends)
|
||||
case *Channel:
|
||||
recipientSessions = target.sessionsWithCap(caps.Metadata)
|
||||
default:
|
||||
return // impossible
|
||||
}
|
||||
|
||||
// don't notify the session that made the change
|
||||
notify.Remove(session)
|
||||
broadcastMetadataUpdate(server, recipientSessions, session, targetName, key, value)
|
||||
}
|
||||
|
||||
for s := range notify {
|
||||
if !s.isSubscribedTo(key) {
|
||||
func broadcastMetadataUpdate(server *Server, sessions iter.Seq[*Session], originator *Session, target, key, value string) {
|
||||
for s := range sessions {
|
||||
// don't notify the session that made the change
|
||||
if s == originator || !s.isSubscribedTo(key) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue