mirror of
https://github.com/ergochat/ergo.git
synced 2026-01-26 21:39:21 -08:00
fix #2307
Add METADATA to the response for new subscriptions; generation of this response is throttled, even though subscription itself is not, so if you're throttled the subscription will succeed but you won't get METADATA lines.
This commit is contained in:
parent
d5fb189a55
commit
9484334e4f
4 changed files with 71 additions and 2 deletions
|
|
@ -823,7 +823,7 @@ func (client *Client) applyPreregMetadata(session *Session) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO this is expensive
|
||||
// note: this is expensive but it's comparable to destroy(), OK to do once per session
|
||||
friends := client.FriendsMonitors(caps.Metadata)
|
||||
for _, s := range client.Sessions() {
|
||||
if s != session {
|
||||
|
|
|
|||
|
|
@ -895,6 +895,23 @@ func (channel *Channel) GetMetadata(key string) (string, bool) {
|
|||
return val, ok
|
||||
}
|
||||
|
||||
type MetadataPair struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
func (channel *Channel) GetMetadataBulk(keys []string) (result []MetadataPair) {
|
||||
channel.stateMutex.RLock()
|
||||
defer channel.stateMutex.RUnlock()
|
||||
|
||||
for _, k := range keys {
|
||||
if val, ok := channel.metadata[k]; ok {
|
||||
result = append(result, MetadataPair{Key: k, Value: val})
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (channel *Channel) SetMetadata(key string, value string, limit int) (updated bool, err error) {
|
||||
defer channel.MarkDirty(IncludeAllAttrs)
|
||||
|
||||
|
|
@ -962,6 +979,18 @@ func (client *Client) GetMetadata(key string) (string, bool) {
|
|||
return val, ok
|
||||
}
|
||||
|
||||
func (client *Client) GetMetadataBulk(keys []string) (result []MetadataPair) {
|
||||
client.stateMutex.RLock()
|
||||
defer client.stateMutex.RUnlock()
|
||||
|
||||
for _, k := range keys {
|
||||
if val, ok := client.metadata[k]; ok {
|
||||
result = append(result, MetadataPair{Key: k, Value: val})
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (client *Client) SetMetadata(key string, value string, limit int) (updated bool, err error) {
|
||||
var alwaysOn bool
|
||||
defer func() {
|
||||
|
|
|
|||
|
|
@ -3375,6 +3375,12 @@ func metadataSubsHandler(client *Client, subcommand string, params []string, rb
|
|||
rb.Add(nil, server.name, RPL_METADATASUBOK, params...)
|
||||
}
|
||||
|
||||
if client.registered && len(added) != 0 {
|
||||
if throttled, _ := client.checkMetadataThrottle(); !throttled {
|
||||
processMetadataNewSubscriptions(client, rb, added)
|
||||
}
|
||||
}
|
||||
|
||||
case "unsub":
|
||||
keys := params[2:]
|
||||
removed := rb.session.UnsubscribeFrom(keys...)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/ergochat/ergo/irc/caps"
|
||||
"github.com/ergochat/ergo/irc/modes"
|
||||
"github.com/ergochat/ergo/irc/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -35,7 +36,6 @@ func notifySubscribers(server *Server, session *Session, targetObj MetadataHaver
|
|||
|
||||
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() {
|
||||
|
|
@ -126,6 +126,40 @@ func playMetadataVerbBatch(rb *ResponseBuffer, target string, values map[string]
|
|||
}
|
||||
}
|
||||
|
||||
func processMetadataNewSubscriptions(client *Client, rb *ResponseBuffer, subs []string) {
|
||||
// "When subscribing to a key, clients SHOULD receive the current value
|
||||
// of that key for channels/users they are receiving updates for."
|
||||
// note that this is expensive because we need to compute the friends
|
||||
visibility := "*"
|
||||
friendsSeen := make(utils.HashSet[*Client])
|
||||
for _, channel := range client.Channels() {
|
||||
chname := channel.Name()
|
||||
for _, pair := range channel.GetMetadataBulk(subs) {
|
||||
rb.Add(nil, client.server.name, "METADATA", chname, pair.Key, visibility, pair.Value)
|
||||
}
|
||||
for _, friend := range channel.Members() {
|
||||
if friendsSeen.Has(friend) {
|
||||
continue
|
||||
}
|
||||
friendsSeen.Add(friend)
|
||||
for _, pair := range friend.GetMetadataBulk(subs) {
|
||||
rb.Add(nil, client.server.name, "METADATA", friend.Nick(), pair.Key, visibility, pair.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, friendNick := range client.server.monitorManager.List(rb.session) {
|
||||
friend := client.server.clients.Get(friendNick)
|
||||
if friend == nil || friendsSeen.Has(friend) {
|
||||
continue
|
||||
}
|
||||
friendsSeen.Add(friend)
|
||||
for _, pair := range friend.GetMetadataBulk(subs) {
|
||||
rb.Add(nil, client.server.name, "METADATA", friend.Nick(), pair.Key, visibility, pair.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var validMetadataKeyRegexp = regexp.MustCompile("^[a-z0-9_./-]+$")
|
||||
|
||||
func metadataKeyIsEvil(key string) bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue