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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"iter"
|
||||||
"maps"
|
"maps"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -1676,6 +1677,20 @@ func (channel *Channel) auditoriumFriends(client *Client) (friends []*Client) {
|
||||||
return
|
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
|
// returns whether the client is visible to unprivileged users in the channel
|
||||||
// (i.e., respecting auditorium mode). note that this assumes that the client
|
// (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
|
// 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)
|
targetChannel = server.channels.Get(target)
|
||||||
if targetChannel != nil {
|
if targetChannel != nil {
|
||||||
targetObj = targetChannel
|
targetObj = targetChannel
|
||||||
|
target = targetChannel.Name() // canonicalize case
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
targetClient = server.clients.Get(target)
|
targetClient = server.clients.Get(target)
|
||||||
if targetClient != nil {
|
if targetClient != nil {
|
||||||
targetObj = targetClient
|
targetObj = targetClient
|
||||||
|
target = targetClient.Nick() // canonicalize case
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if targetObj == nil {
|
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)
|
server.logger.Debug("metadata", "setting", key, value, "on", target)
|
||||||
|
|
||||||
targetObj.SetMetadata(key, value)
|
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)
|
rb.Add(nil, server.name, RPL_KEYVALUE, client.Nick(), originalTarget, key, "*", value)
|
||||||
} else {
|
} else {
|
||||||
server.logger.Debug("metadata", "deleting", key, "on", target)
|
server.logger.Debug("metadata", "deleting", key, "on", target)
|
||||||
|
// TODO check success or failure here
|
||||||
targetObj.DeleteMetadata(key)
|
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"))
|
rb.Add(nil, server.name, RPL_KEYNOTSET, client.Nick(), target, key, client.t("Key deleted"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ package irc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"iter"
|
||||||
|
"maps"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ergochat/ergo/irc/caps"
|
"github.com/ergochat/ergo/irc/caps"
|
||||||
"github.com/ergochat/ergo/irc/modes"
|
"github.com/ergochat/ergo/irc/modes"
|
||||||
"github.com/ergochat/ergo/irc/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -24,34 +25,31 @@ type MetadataHaver = interface {
|
||||||
CountMetadata() int
|
CountMetadata() int
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifySubscribers(server *Server, session *Session, target string, key string, value string) {
|
func notifySubscribers(server *Server, session *Session, targetObj MetadataHaver, targetName, key, value string) {
|
||||||
var notify utils.HashSet[*Session] = make(utils.HashSet[*Session])
|
var recipientSessions iter.Seq[*Session]
|
||||||
targetChannel := server.channels.Get(target)
|
|
||||||
targetClient := server.clients.Get(target)
|
|
||||||
|
|
||||||
if targetClient != nil {
|
switch target := targetObj.(type) {
|
||||||
notify = targetClient.FriendsMonitors(caps.Metadata)
|
case *Client:
|
||||||
// notify clients about changes regarding themselves
|
// TODO this case is expensive and might warrant rate-limiting
|
||||||
for _, s := range targetClient.Sessions() {
|
friends := target.FriendsMonitors(caps.Metadata)
|
||||||
notify.Add(s)
|
// broadcast metadata update to other connected sessions
|
||||||
}
|
for _, s := range target.Sessions() {
|
||||||
}
|
friends.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
recipientSessions = maps.Keys(friends)
|
||||||
|
case *Channel:
|
||||||
|
recipientSessions = target.sessionsWithCap(caps.Metadata)
|
||||||
|
default:
|
||||||
|
return // impossible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
broadcastMetadataUpdate(server, recipientSessions, session, targetName, key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// don't notify the session that made the change
|
||||||
notify.Remove(session)
|
if s == originator || !s.isSubscribedTo(key) {
|
||||||
|
|
||||||
for s := range notify {
|
|
||||||
if !s.isSubscribedTo(key) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue