Skip to content

Commit 8798676

Browse files
authored
update metadata corresponding to spec edits (#2282)
* spec update: metadata keys are lowercase * add batch parameter to metadata batches * fix: connecting clients receive METADATA, not RPL_KEYVALUE * spec update: send RPL_METADATASUBS in a metadata-subs batch * move some helpers * bump irctest to forked hash This is progval/irctest#314 but I don't want to couple the merges * fix: empty value is valid * fix: deleting a nonexistent key gets a FAIL
1 parent cca400d commit 8798676

File tree

6 files changed

+43
-26
lines changed

6 files changed

+43
-26
lines changed

irc/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,7 @@ func (client *Client) applyPreregMetadata(session *Session) {
828828

829829
target := client.Nick()
830830
for k, v := range updates {
831-
broadcastMetadataUpdate(client.server, maps.Keys(friends), session, target, k, v)
831+
broadcastMetadataUpdate(client.server, maps.Keys(friends), session, target, k, v, true)
832832
}
833833
}
834834

irc/handlers.go

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3195,14 +3195,15 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
31953195
// echo the value to the client whether or not there was a real update
31963196
rb.Add(nil, server.name, RPL_KEYVALUE, client.Nick(), target, key, "*", value)
31973197
if updated {
3198-
notifySubscribers(server, rb.session, targetObj, target, key, value)
3198+
notifySubscribers(server, rb.session, targetObj, target, key, value, true)
31993199
}
32003200
} else {
32013201
if updated := targetObj.DeleteMetadata(key); updated {
3202-
notifySubscribers(server, rb.session, targetObj, target, key, "")
3202+
notifySubscribers(server, rb.session, targetObj, target, key, "", false)
3203+
rb.Add(nil, server.name, RPL_KEYNOTSET, client.Nick(), target, key, client.t("Key deleted"))
3204+
} else {
3205+
rb.Add(nil, server.name, "FAIL", "METADATA", "KEY_NOT_SET", utils.SafeErrorParam(key), client.t("Metadata key not set"))
32033206
}
3204-
// acknowledge to the client whether or not there was a real update
3205-
rb.Add(nil, server.name, RPL_KEYNOTSET, client.Nick(), target, key, client.t("Key deleted"))
32063207
}
32073208

32083209
case "get":
@@ -3211,7 +3212,7 @@ func metadataRegisteredHandler(client *Client, config *Config, subcommand string
32113212
return
32123213
}
32133214

3214-
batchId := rb.StartNestedBatch("metadata")
3215+
batchId := rb.StartNestedBatch("metadata", target)
32153216
defer rb.EndNestedBatch(batchId)
32163217

32173218
for _, key := range params[2:] {
@@ -3355,6 +3356,9 @@ func metadataSubsHandler(client *Client, subcommand string, params []string, rb
33553356

33563357
subs := rb.session.MetadataSubscriptions()
33573358

3359+
batchID := rb.StartNestedBatch("metadata-subs")
3360+
defer rb.EndNestedBatch(batchID)
3361+
33583362
chunked := utils.ChunkifyParams(maps.Keys(subs), lineLength)
33593363
for _, line := range chunked {
33603364
params := append([]string{client.Nick()}, line...)
@@ -3364,16 +3368,6 @@ func metadataSubsHandler(client *Client, subcommand string, params []string, rb
33643368
return false
33653369
}
33663370

3367-
func playMetadataList(rb *ResponseBuffer, nick, target string, values map[string]string) {
3368-
batchId := rb.StartNestedBatch("metadata")
3369-
defer rb.EndNestedBatch(batchId)
3370-
3371-
for key, val := range values {
3372-
visibility := "*"
3373-
rb.Add(nil, rb.session.client.server.name, RPL_KEYVALUE, nick, target, key, visibility, val)
3374-
}
3375-
}
3376-
33773371
// REHASH
33783372
func rehashHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
33793373
nick := client.Nick()

irc/metadata.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type MetadataHaver = interface {
3030
CountMetadata() int
3131
}
3232

33-
func notifySubscribers(server *Server, session *Session, targetObj MetadataHaver, targetName, key, value string) {
33+
func notifySubscribers(server *Server, session *Session, targetObj MetadataHaver, targetName, key, value string, set bool) {
3434
var recipientSessions iter.Seq[*Session]
3535

3636
switch target := targetObj.(type) {
@@ -48,17 +48,17 @@ func notifySubscribers(server *Server, session *Session, targetObj MetadataHaver
4848
return // impossible
4949
}
5050

51-
broadcastMetadataUpdate(server, recipientSessions, session, targetName, key, value)
51+
broadcastMetadataUpdate(server, recipientSessions, session, targetName, key, value, set)
5252
}
5353

54-
func broadcastMetadataUpdate(server *Server, sessions iter.Seq[*Session], originator *Session, target, key, value string) {
54+
func broadcastMetadataUpdate(server *Server, sessions iter.Seq[*Session], originator *Session, target, key, value string, set bool) {
5555
for s := range sessions {
5656
// don't notify the session that made the change
5757
if s == originator || !s.isSubscribedTo(key) {
5858
continue
5959
}
6060

61-
if value != "" {
61+
if set {
6262
s.Send(nil, server.name, "METADATA", target, key, "*", value)
6363
} else {
6464
s.Send(nil, server.name, "METADATA", target, key, "*")
@@ -67,7 +67,7 @@ func broadcastMetadataUpdate(server *Server, sessions iter.Seq[*Session], origin
6767
}
6868

6969
func syncClientMetadata(server *Server, rb *ResponseBuffer, target *Client) {
70-
batchId := rb.StartNestedBatch("metadata")
70+
batchId := rb.StartNestedBatch("metadata", target.Nick())
7171
defer rb.EndNestedBatch(batchId)
7272

7373
subs := rb.session.MetadataSubscriptions()
@@ -81,7 +81,7 @@ func syncClientMetadata(server *Server, rb *ResponseBuffer, target *Client) {
8181
}
8282

8383
func syncChannelMetadata(server *Server, rb *ResponseBuffer, channel *Channel) {
84-
batchId := rb.StartNestedBatch("metadata")
84+
batchId := rb.StartNestedBatch("metadata", channel.Name())
8585
defer rb.EndNestedBatch(batchId)
8686

8787
subs := rb.session.MetadataSubscriptions()
@@ -106,7 +106,27 @@ func syncChannelMetadata(server *Server, rb *ResponseBuffer, channel *Channel) {
106106
}
107107
}
108108

109-
var validMetadataKeyRegexp = regexp.MustCompile("^[A-Za-z0-9_./-]+$")
109+
func playMetadataList(rb *ResponseBuffer, nick, target string, values map[string]string) {
110+
batchId := rb.StartNestedBatch("metadata", target)
111+
defer rb.EndNestedBatch(batchId)
112+
113+
for key, val := range values {
114+
visibility := "*"
115+
rb.Add(nil, rb.session.client.server.name, RPL_KEYVALUE, nick, target, key, visibility, val)
116+
}
117+
}
118+
119+
func playMetadataVerbBatch(rb *ResponseBuffer, target string, values map[string]string) {
120+
batchId := rb.StartNestedBatch("metadata", target)
121+
defer rb.EndNestedBatch(batchId)
122+
123+
for key, val := range values {
124+
visibility := "*"
125+
rb.Add(nil, rb.session.client.server.name, "METADATA", target, key, visibility, val)
126+
}
127+
}
128+
129+
var validMetadataKeyRegexp = regexp.MustCompile("^[a-z0-9_./-]+$")
110130

111131
func metadataKeyIsEvil(key string) bool {
112132
return !validMetadataKeyRegexp.MatchString(key)

irc/metadata_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ func TestKeyCheck(t *testing.T) {
77
input string
88
isEvil bool
99
}{
10-
{"ImNormal", false},
10+
{"ImNormalButIHaveCaps", true},
11+
{"imnormalandidonthavecaps", false},
12+
{"ergo.chat/vendor-extension", false},
1113
{"", true},
1214
{":imevil", true},
15+
{"im:evil", true},
1316
{"key£with$not%allowed^chars", true},
1417
{"key.thats_completely/normal-and.fine", false},
1518
}

irc/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ func (server *Server) playRegistrationBurst(session *Session) {
499499
server.RplISupport(c, rb)
500500
}
501501
if session.capabilities.Has(caps.Metadata) {
502-
playMetadataList(rb, d.nick, d.nick, c.ListMetadata())
502+
playMetadataVerbBatch(rb, d.nick, c.ListMetadata())
503503
}
504504
if d.account != "" && session.capabilities.Has(caps.Persistence) {
505505
reportPersistenceStatus(c, rb, false)

irctest

0 commit comments

Comments
 (0)