mirror of
https://github.com/jeremyd/ergo.git
synced 2026-08-01 11:43:06 -07:00
update to draft/metadata-3 (#2416)
temporarily update irctest to metadata-3 branch
This commit is contained in:
committed by
GitHub
parent
c6b2f1285c
commit
26cf806545
+7
-3
@@ -238,7 +238,7 @@ CAPDEFS = [
|
||||
standard="Soju/Goguma vendor",
|
||||
),
|
||||
CapDef(
|
||||
identifier="Metadata",
|
||||
identifier="MetadataDraft2",
|
||||
name="draft/metadata-2",
|
||||
url="https://ircv3.net/specs/extensions/metadata",
|
||||
standard="draft IRCv3",
|
||||
@@ -249,8 +249,12 @@ CAPDEFS = [
|
||||
url="https://github.com/ircv3/ircv3-specifications/pull/602",
|
||||
standard="proposed IRCv3",
|
||||
),
|
||||
|
||||
|
||||
CapDef(
|
||||
identifier="Metadata",
|
||||
name="draft/metadata-3",
|
||||
url="https://github.com/ircv3/ircv3-specifications/pull/613",
|
||||
standard="draft IRCv3",
|
||||
),
|
||||
]
|
||||
|
||||
def validate_defs():
|
||||
|
||||
@@ -70,6 +70,8 @@ const (
|
||||
// authtoken draft: https://github.com/ircv3/ircv3-specifications/pull/602
|
||||
AuthTokenBatchType = "draft/authtoken"
|
||||
AuthToken005 = "draft/AUTHTOKEN"
|
||||
|
||||
MetadataSyncAllTarget = "*ALL"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
+7
-2
@@ -7,7 +7,7 @@ package caps
|
||||
|
||||
const (
|
||||
// number of recognized capabilities:
|
||||
numCapabs = 39
|
||||
numCapabs = 40
|
||||
// length of the uint32 array that represents the bitset:
|
||||
bitsetLen = 2
|
||||
)
|
||||
@@ -69,8 +69,12 @@ const (
|
||||
// https://github.com/progval/ircv3-specifications/blob/redaction/extensions/message-redaction.md
|
||||
MessageRedaction Capability = iota
|
||||
|
||||
// Metadata is the draft IRCv3 capability named "draft/metadata-2":
|
||||
// MetadataDraft2 is the draft IRCv3 capability named "draft/metadata-2":
|
||||
// https://ircv3.net/specs/extensions/metadata
|
||||
MetadataDraft2 Capability = iota
|
||||
|
||||
// Metadata is the draft IRCv3 capability named "draft/metadata-3":
|
||||
// https://github.com/ircv3/ircv3-specifications/pull/613
|
||||
Metadata Capability = iota
|
||||
|
||||
// Multiline is the proposed IRCv3 capability named "draft/multiline":
|
||||
@@ -188,6 +192,7 @@ var (
|
||||
"draft/languages",
|
||||
"draft/message-redaction",
|
||||
"draft/metadata-2",
|
||||
"draft/metadata-3",
|
||||
"draft/multiline",
|
||||
"draft/persistence",
|
||||
"draft/pre-away",
|
||||
|
||||
@@ -822,6 +822,11 @@ func (client *Client) performReattach(session *Session) {
|
||||
rb.Send(true)
|
||||
}
|
||||
session.autoreplayMissedSince = time.Time{}
|
||||
if session.capabilities.Has(caps.Metadata) {
|
||||
rb := NewResponseBuffer(session)
|
||||
syncAllMetadata(client.server, rb)
|
||||
rb.Send(true)
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) applyPreregMetadata(session *Session) {
|
||||
|
||||
@@ -1778,6 +1778,7 @@ func LoadConfig(filename string) (config *Config, err error) {
|
||||
|
||||
if !config.Metadata.Enabled {
|
||||
config.Server.supportedCaps.Disable(caps.Metadata)
|
||||
config.Server.supportedCaps.Disable(caps.MetadataDraft2)
|
||||
} else {
|
||||
metadataValues := make([]string, 0, 4)
|
||||
metadataValues = append(metadataValues, "before-connect")
|
||||
@@ -1795,6 +1796,7 @@ func LoadConfig(filename string) (config *Config, err error) {
|
||||
metadataValues = append(metadataValues, fmt.Sprintf("max-value-bytes=%d", config.Metadata.MaxValueBytes))
|
||||
}
|
||||
config.Server.capValues[caps.Metadata] = strings.Join(metadataValues, ",")
|
||||
config.Server.capValues[caps.MetadataDraft2] = strings.Join(metadataValues, ",")
|
||||
}
|
||||
|
||||
err = config.processExtjwt()
|
||||
|
||||
@@ -923,6 +923,22 @@ func (channel *Channel) ListMetadata() map[string]string {
|
||||
return maps.Clone(channel.metadata)
|
||||
}
|
||||
|
||||
func (channel *Channel) ListSubscribedMetadata(subscriptions utils.HashSet[string]) (result map[string]string) {
|
||||
channel.stateMutex.RLock()
|
||||
defer channel.stateMutex.RUnlock()
|
||||
|
||||
for k, v := range channel.metadata {
|
||||
if subscriptions.Has(k) {
|
||||
if result == nil {
|
||||
result = make(map[string]string)
|
||||
}
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (channel *Channel) DeleteMetadata(key string) (updated bool) {
|
||||
defer channel.MarkDirty(IncludeAllAttrs)
|
||||
|
||||
@@ -1032,6 +1048,22 @@ func (client *Client) ListMetadata() map[string]string {
|
||||
return maps.Clone(client.metadata)
|
||||
}
|
||||
|
||||
func (client *Client) ListSubscribedMetadata(subscriptions utils.HashSet[string]) (result map[string]string) {
|
||||
client.stateMutex.RLock()
|
||||
defer client.stateMutex.RUnlock()
|
||||
|
||||
for k, v := range client.metadata {
|
||||
if subscriptions.Has(k) {
|
||||
if result == nil {
|
||||
result = make(map[string]string)
|
||||
}
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (client *Client) DeleteMetadata(key string) (updated bool) {
|
||||
defer func() {
|
||||
if updated {
|
||||
|
||||
+41
-29
@@ -765,6 +765,12 @@ func capHandler(server *Server, client *Client, msg ircmsg.Message, rb *Response
|
||||
rb.session.capabilities.Subtract(toRemove)
|
||||
rb.Add(nil, server.name, "CAP", details.nick, "ACK", capString)
|
||||
|
||||
// XXX compatibility hack, if draft/metadata-2 was requested, silently enable draft/metadata-3
|
||||
// this way we only have to check for one cap at runtime
|
||||
if rb.session.capabilities.Has(caps.MetadataDraft2) {
|
||||
rb.session.capabilities.Add(caps.Metadata)
|
||||
}
|
||||
|
||||
case "END":
|
||||
if !client.registered {
|
||||
rb.session.capState = caps.NegotiatedState
|
||||
@@ -3275,7 +3281,7 @@ func metadataHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
|
||||
return metadataUnregisteredHandler(client, config, subcommand, msg.Params, rb)
|
||||
}
|
||||
default:
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "SUBCOMMAND_INVALID", utils.SafeErrorParam(msg.Params[1]), client.t("Invalid subcommand"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_PARAMS", utils.SafeErrorParam(msg.Params[1]), client.t("Invalid subcommand"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -3296,7 +3302,10 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
var targetObj MetadataHaver
|
||||
var targetClient *Client
|
||||
var targetChannel *Channel
|
||||
if strings.HasPrefix(target, "#") {
|
||||
var syncAll bool
|
||||
if subcommand == "sync" && strings.EqualFold(target, caps.MetadataSyncAllTarget) {
|
||||
syncAll = true
|
||||
} else if strings.HasPrefix(target, "#") {
|
||||
targetChannel = server.channels.Get(target)
|
||||
if targetChannel != nil {
|
||||
targetObj = targetChannel
|
||||
@@ -3309,7 +3318,7 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
target = targetClient.Nick() // canonicalize case
|
||||
}
|
||||
}
|
||||
if targetObj == nil {
|
||||
if !syncAll && targetObj == nil {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_TARGET", target, client.t("Invalid metadata target"))
|
||||
return
|
||||
}
|
||||
@@ -3318,7 +3327,7 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
case "set":
|
||||
key := params[2]
|
||||
if metadataKeyIsEvil(key) {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_INVALID", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_KEY", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3339,19 +3348,19 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
}
|
||||
}
|
||||
|
||||
if len(params) > 3 {
|
||||
if len(params) > 3 && params[3] != "" {
|
||||
value := params[3]
|
||||
|
||||
config := client.server.Config()
|
||||
if failMsg := metadataValueIsEvil(config, key, value); failMsg != "" {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "VALUE_INVALID", client.t(failMsg))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_VALUE", utils.SafeErrorParam(key), client.t(failMsg))
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := targetObj.SetMetadata(key, value, config.Metadata.MaxKeys)
|
||||
if err != nil {
|
||||
// errLimitExceeded is the only possible error
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "LIMIT_REACHED", client.t("Too many metadata keys"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "LIMIT_REACHED", target, strconv.Itoa(config.Metadata.MaxKeys), client.t("Too many metadata keys"))
|
||||
return
|
||||
}
|
||||
// echo the value to the client whether or not there was a real update
|
||||
@@ -3360,11 +3369,10 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
notifySubscribers(server, rb.session, targetObj, target, key, value, true)
|
||||
}
|
||||
} else {
|
||||
if updated := targetObj.DeleteMetadata(key); updated {
|
||||
updated := targetObj.DeleteMetadata(key)
|
||||
rb.Add(nil, server.name, RPL_KEYNOTSET, client.Nick(), target, key, client.t("Key deleted"))
|
||||
if updated {
|
||||
notifySubscribers(server, rb.session, targetObj, target, key, "", false)
|
||||
rb.Add(nil, server.name, RPL_KEYNOTSET, client.Nick(), target, key, client.t("Key deleted"))
|
||||
} else {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_NOT_SET", utils.SafeErrorParam(key), client.t("Metadata key not set"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3389,7 +3397,7 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
|
||||
for _, key := range params[2:] {
|
||||
if metadataKeyIsEvil(key) {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_INVALID", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_KEY", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -3412,6 +3420,10 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
|
||||
playMetadataList(rb, client.Nick(), target, targetObj.ListMetadata())
|
||||
|
||||
case "sync":
|
||||
if syncAll {
|
||||
syncAllMetadata(server, rb)
|
||||
return
|
||||
}
|
||||
if !metadataCanISeeThisTarget(client, targetObj) {
|
||||
noKeyPerms("*")
|
||||
return
|
||||
@@ -3446,32 +3458,27 @@ func metadataUnregisteredHandler(client *Client, config *Config, subcommand stri
|
||||
}
|
||||
key := params[2]
|
||||
if metadataKeyIsEvil(key) {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_INVALID", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_KEY", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
return
|
||||
}
|
||||
if len(params) >= 4 {
|
||||
if len(params) > 3 && params[3] != "" {
|
||||
value := params[3]
|
||||
// enforce a sane limit on prereg keys. we don't need to enforce the exact limit,
|
||||
// that will be done when applying the buffer after registration
|
||||
if len(rb.session.metadataPreregVals) > config.Metadata.MaxKeys {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "LIMIT_REACHED", client.t("Too many metadata keys"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "LIMIT_REACHED", "*", strconv.Itoa(config.Metadata.MaxKeys), client.t("Too many metadata keys"))
|
||||
return
|
||||
}
|
||||
if failMsg := metadataValueIsEvil(config, key, value); failMsg != "" {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "VALUE_INVALID", client.t(failMsg))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_VALUE", utils.SafeErrorParam(key), client.t(failMsg))
|
||||
return
|
||||
}
|
||||
rb.session.metadataPreregVals[key] = value
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, "*", "*", key, "*", value)
|
||||
} else {
|
||||
// unset
|
||||
_, present := rb.session.metadataPreregVals[key]
|
||||
if present {
|
||||
delete(rb.session.metadataPreregVals, key)
|
||||
rb.Add(nil, server.name, RPL_KEYNOTSET, "*", "*", key, client.t("Key deleted"))
|
||||
} else {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_NOT_SET", utils.SafeErrorParam(key), client.t("Metadata key not set"))
|
||||
}
|
||||
delete(rb.session.metadataPreregVals, key)
|
||||
rb.Add(nil, server.name, RPL_KEYNOTSET, "*", "*", key, client.t("Key deleted"))
|
||||
}
|
||||
case "list":
|
||||
playMetadataList(rb, "*", "*", rb.session.metadataPreregVals)
|
||||
@@ -3480,7 +3487,7 @@ func metadataUnregisteredHandler(client *Client, config *Config, subcommand stri
|
||||
rb.session.metadataPreregVals = nil
|
||||
playMetadataList(rb, "*", "*", oldMetadata)
|
||||
case "sync":
|
||||
rb.Add(nil, server.name, RPL_METADATASYNCLATER, "*", utils.SafeErrorParam(params[1]), "60") // lol
|
||||
rb.Add(nil, server.name, RPL_METADATASYNCLATER, "*", utils.SafeErrorParam(params[1]), "60", "Try again later") // lol
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -3494,24 +3501,29 @@ func metadataSubsHandler(client *Client, subcommand string, params []string, rb
|
||||
keys := params[2:]
|
||||
for _, key := range keys {
|
||||
if metadataKeyIsEvil(key) {
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_INVALID", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "INVALID_KEY", utils.SafeErrorParam(key), client.t("Invalid key name"))
|
||||
return
|
||||
}
|
||||
}
|
||||
added, err := rb.session.SubscribeTo(keys...)
|
||||
if err == errMetadataTooManySubs {
|
||||
bad := keys[len(added)] // get the key that broke the camel's back
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "TOO_MANY_SUBS", utils.SafeErrorParam(bad), client.t("Too many subscriptions"))
|
||||
limit := strconv.Itoa(server.Config().Metadata.MaxSubs)
|
||||
rb.Add(nil, server.name, "FAIL", "METADATA", "LIMIT_REACHED", utils.SafeErrorParam(bad), limit, client.t("Too many subscriptions"))
|
||||
}
|
||||
|
||||
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATASUBOK) - len(client.Nick()) - 10
|
||||
|
||||
nick := client.Nick()
|
||||
lineLength := MaxLineLen - len(server.name) - len(RPL_METADATASUBOK) - len(nick) - 10
|
||||
chunked := utils.ChunkifyParams(slices.Values(added), lineLength)
|
||||
for _, line := range chunked {
|
||||
params := append([]string{client.Nick()}, line...)
|
||||
params := append([]string{nick}, line...)
|
||||
rb.Add(nil, server.name, RPL_METADATASUBOK, params...)
|
||||
}
|
||||
|
||||
if client.registered && len(added) != 0 {
|
||||
rb.Add(nil, server.name, RPL_METADATASYNCLATER, "*", caps.MetadataSyncAllTarget, "0", client.t("Try again later"))
|
||||
}
|
||||
|
||||
case "unsub":
|
||||
keys := params[2:]
|
||||
removed := rb.session.UnsubscribeFrom(keys...)
|
||||
|
||||
+63
-6
@@ -59,9 +59,9 @@ func broadcastMetadataUpdate(server *Server, sessions iter.Seq[*Session], origin
|
||||
}
|
||||
|
||||
if set {
|
||||
s.Send(nil, server.name, "METADATA", target, key, "*", value)
|
||||
s.Send(nil, server.name, RPL_KEYVALUE, "*", target, key, "*", value)
|
||||
} else {
|
||||
s.Send(nil, server.name, "METADATA", target, key, "*")
|
||||
s.Send(nil, server.name, RPL_KEYNOTSET, "*", target, key, s.client.t("Key deleted"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func syncClientMetadata(server *Server, rb *ResponseBuffer, target *Client) {
|
||||
for k, v := range values {
|
||||
if subs.Has(k) {
|
||||
visibility := "*"
|
||||
rb.Add(nil, server.name, "METADATA", target.Nick(), k, visibility, v)
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, "*", target.Nick(), k, visibility, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ func syncChannelMetadata(server *Server, rb *ResponseBuffer, channel *Channel) {
|
||||
for k, v := range values {
|
||||
if subs.Has(k) {
|
||||
visibility := "*"
|
||||
rb.Add(nil, server.name, "METADATA", chname, k, visibility, v)
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, "*", chname, k, visibility, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,12 +100,63 @@ func syncChannelMetadata(server *Server, rb *ResponseBuffer, channel *Channel) {
|
||||
for k, v := range values {
|
||||
if subs.Has(k) {
|
||||
visibility := "*"
|
||||
rb.Add(nil, server.name, "METADATA", client.Nick(), k, visibility, v)
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, "*", client.Nick(), k, visibility, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncAllMetadata(server *Server, rb *ResponseBuffer) {
|
||||
client := rb.session.client
|
||||
|
||||
batchID := rb.StartNestedBatch(nil, "metadata", "*ALL")
|
||||
defer rb.EndNestedBatch(batchID)
|
||||
|
||||
subs := rb.session.MetadataSubscriptions()
|
||||
if len(subs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// deduplicate friends across channels
|
||||
friendsWithMetadata := make(map[*Client]map[string]string)
|
||||
// include the client even if they have no channels
|
||||
friendsWithMetadata[client] = client.ListSubscribedMetadata(subs)
|
||||
|
||||
visibility := "*"
|
||||
|
||||
for _, channel := range client.Channels() {
|
||||
chname := channel.Name()
|
||||
values := channel.ListSubscribedMetadata(subs)
|
||||
for k, v := range values {
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, "*", chname, k, visibility, v)
|
||||
}
|
||||
|
||||
for _, member := range channel.Members() {
|
||||
if _, ok := friendsWithMetadata[member]; !ok {
|
||||
friendsWithMetadata[member] = member.ListSubscribedMetadata(subs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, watchedNick := range server.monitorManager.List(rb.session) {
|
||||
if watched := server.clients.Get(watchedNick); watched != nil {
|
||||
if _, ok := friendsWithMetadata[watched]; !ok {
|
||||
friendsWithMetadata[watched] = watched.ListSubscribedMetadata(subs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for friend, friendMetadata := range friendsWithMetadata {
|
||||
if friendMetadata == nil {
|
||||
continue
|
||||
}
|
||||
nick := friend.Nick()
|
||||
for k, v := range friendMetadata {
|
||||
rb.Add(nil, server.name, RPL_KEYVALUE, "*", nick, k, visibility, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func playMetadataList(rb *ResponseBuffer, nick, target string, values map[string]string) {
|
||||
batchId := rb.StartNestedBatch(nil, "metadata", target)
|
||||
defer rb.EndNestedBatch(batchId)
|
||||
@@ -131,7 +182,7 @@ func playMetadataVerbBatch(rb *ResponseBuffer, target string, values map[string]
|
||||
|
||||
for key, val := range values {
|
||||
visibility := "*"
|
||||
rb.Add(nil, rb.session.client.server.name, "METADATA", target, key, visibility, val)
|
||||
rb.Add(nil, rb.session.client.server.name, RPL_KEYVALUE, "*", target, key, visibility, val)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +197,12 @@ func metadataValueIsEvil(config *Config, key, value string) (failMsg string) {
|
||||
return `METADATA values must be UTF-8`
|
||||
}
|
||||
|
||||
if value == "" {
|
||||
// we should never hit this case,
|
||||
// since the command handlers should interpret empty value as "delete"
|
||||
return `METADATA value MUST NOT be empty`
|
||||
}
|
||||
|
||||
if len(key)+len(value) > maxCombinedMetadataLenBytes ||
|
||||
(config.Metadata.MaxValueBytes > 0 && len(value) > config.Metadata.MaxValueBytes) {
|
||||
|
||||
|
||||
+13
-4
@@ -64,12 +64,19 @@ func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool, clie
|
||||
for _, session := range watchers {
|
||||
session.Send(nil, session.client.server.name, command, session.client.Nick(), nick)
|
||||
|
||||
if metadata != nil && session.capabilities.Has(caps.Metadata) {
|
||||
for key := range session.MetadataSubscriptions() {
|
||||
if online && session.capabilities.Has(caps.Metadata) {
|
||||
// even if there is no user metadata, or no subscriptions,
|
||||
// we still need to send an empty metadata batch alongside RPL_MONONLINE
|
||||
subs := session.MetadataSubscriptions()
|
||||
rb := NewResponseBuffer(session)
|
||||
batchID := rb.StartNestedBatch(nil, "metadata", nick)
|
||||
for key := range subs {
|
||||
if val, ok := metadata[key]; ok {
|
||||
session.Send(nil, client.server.name, "METADATA", nick, key, "*", val)
|
||||
rb.Add(nil, client.server.name, RPL_KEYVALUE, "*", nick, key, "*", val)
|
||||
}
|
||||
}
|
||||
rb.EndNestedBatch(batchID)
|
||||
rb.Send(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +136,9 @@ func (manager *MonitorManager) RemoveAll(session *Session) {
|
||||
func (manager *MonitorManager) List(session *Session) (nicks []string) {
|
||||
manager.RLock()
|
||||
defer manager.RUnlock()
|
||||
for _, nick := range manager.watching[session] {
|
||||
watching := manager.watching[session]
|
||||
nicks = make([]string, 0, len(watching))
|
||||
for _, nick := range watching {
|
||||
nicks = append(nicks, nick)
|
||||
}
|
||||
return nicks
|
||||
|
||||
@@ -478,6 +478,12 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
|
||||
server.handleAutojoins(session, config.Channels.AutoJoin)
|
||||
}
|
||||
|
||||
if session.capabilities.Has(caps.Metadata) {
|
||||
rb := NewResponseBuffer(session)
|
||||
syncAllMetadata(server, rb)
|
||||
rb.Send(true)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule irctest updated: d18d6e35fe...21c620bc9c
Reference in New Issue
Block a user