-
Notifications
You must be signed in to change notification settings - Fork 218
metadata-2 #2273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
metadata-2 #2273
Conversation
|
Thank you so much, this is delightful! I'll let @progval weigh in on correctness w.r.t. the specification. I have a brief implementation note: don't write any new code referencing buntdb. Store everything (the metadata itself, the subscription list) as members of the I am in the process of refactoring the account system to have asynchronous persistence, but the corresponding refactor for channels is already done (#2028), so if you want to persist channel metadata, here's how you do it:
As for clients/accounts, don't write any persistence code yet, I will add it as part of the accounts refactor :-) |
|
Ah, I think I was wrong earlier: if the expectation is that metadata subscriptions have to be refreshed by the client on every reconnection, then the correct place to store them is indeed the |
progval
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice, thanks.
First wave of reviews from me, needed so I can run the rest of my tests.
progval
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another round of reviews before I go to bed
| noKeyPerms(key) | ||
| return | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@slingamn Should we check the key is small enough that it's not going to be truncated when sent to other clients? (METADATA * SET display-name :abc is shorter than :irc.example.com METADATA user1 display-name * :abc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this addressed in the spec at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I support adding a preemptive sanity check here, but we probably shouldn't do arithmetic with the server name length, I think it should be more like "key + value are less than 350 bytes"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course not, this is IRC :)
@slingamn This is now in, but there's a problem: calling this during set seems to make the function hang forever. I do not know why this is. |
|
Oh and @progval, I'm finding this bit of the spec somewhat confusing:
My sleep deprived brain interpreted it as "send information about the channel to each user in the channel", but I now realise it's much more likely to mean "send the information about all the channel's participants to the client". I am not a smart person and have no idea if this would actually be a common interpretation, so feel free to disregard. |
slingamn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really nice. @progval can hook you up with the unreleased integration tests for this
irc/metadata.go
Outdated
|
|
||
| type MetadataStore = map[string]string | ||
|
|
||
| type MetadataThing = struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is dead code now....I don't think we're going to implement visibility as part of the MVP for this so we can just use map[string]string for now
irc/metadata.go
Outdated
| members := targetChannel.Members() | ||
| for _, m := range members { | ||
| for _, s := range m.Sessions() { | ||
| notify.Add(s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the cap check up here...
If you want to get adventurous you can actually use iter.Seq here, so the client case will still allocate a hashset of friend sessions (because we need to deduplicate), but the channel case can just iterate over Members() and then Sessions() per member and return applicable sessions without allocating, and then iter.Seq is a common interface for ranging over both of these.
that sounds right |
|
I'm 75% sure this is ready for primetime now. Let me know if something goes wrong!! |
slingamn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting very close to passing Val's tests
|
@thatcher-gaming can you add this functionality?
|
d025e39 to
0cf66d7
Compare
slingamn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I'll leave this open while we do more testing.
irc/getters.go
Outdated
| if session.metadataSubscriptions == nil { | ||
| return false | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can delete this (reads and deletes from the nil map in Go are no-ops like an empty map --- stores will panic)
irc/getters.go
Outdated
| if session.metadataSubscriptions == nil { | ||
| return []string{} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete as per above
| if channel.metadata == nil { | ||
| channel.metadata = make(map[string]string) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete as per above
irc/getters.go
Outdated
| if channel.metadata == nil { | ||
| return 0 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete
irc/getters.go
Outdated
| channel.stateMutex.Lock() | ||
|
|
||
| oldMap := channel.metadata | ||
| channel.metadata = make(map[string]string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
channel.metadata = nil is OK here
irc/getters.go
Outdated
| channel.metadata = make(map[string]string) | ||
|
|
||
| channel.stateMutex.Unlock() | ||
| channel.MarkDirty(IncludeAllAttrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have PTSD from #2149 so my preferred style for all locking is to unlock in a defer, something like this:
defer channel.MarkDirty(IncludeAllAttrs)
channel.stateMutex.Lock()
defer channel.stateMutex.Unlock()
// do the write operation
irc/getters.go
Outdated
| delete(channel.metadata, key) | ||
|
|
||
| channel.stateMutex.Unlock() | ||
| channel.MarkDirty(IncludeAllAttrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see note below about defer
irc/getters.go
Outdated
| return maps.Clone(session.metadataSubscriptions) | ||
| } | ||
|
|
||
| func (channel *Channel) GetMetadata(key string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would return (string, bool) here (the value and ok) --- makes it clearer how to exhaustively handle the success and failure conditions
slingamn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great from an implementation standpoint! I'd like to get another look from @progval on correctness w.r.t. the spec.
This also passes our updated test suite at https://github.com/progval/irctest/tree/metadata2 as mentioned.
| }, | ||
| "metadata": { | ||
| text: `METADATA <target> <subcommand> [<everything else>...] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra whitespace on this line, should be blank
|
I'm going to merge this so I can work on some follow-up tasks. Thanks for the great PR, @thatcher-gaming ! |
|
thanks for all the feedback! sorry about my slightly amateur go knowledge haha |
adds support for most of the draft/metadata-2 spec
fixes #1745
what's new:
metadatasection in the configwhat's missing:
this is a draft because i still need to write some tests but i thought i'd open a pr so someone can tell me if i've done something egregiously wrong (this is my first time doing anything particularly substantial in go (!!!!))