-
Notifications
You must be signed in to change notification settings - Fork 258
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
feat(knocking): process knocked rooms separately during sync #4128
Conversation
73bf2f4
to
383b09d
Compare
I just rebased the changes to avoid a |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4128 +/- ##
==========================================
+ Coverage 84.72% 84.74% +0.01%
==========================================
Files 269 269
Lines 28779 28836 +57
==========================================
+ Hits 24384 24437 +53
- Misses 4395 4399 +4 ☔ View full report in Codecov by Sentry. |
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 promising. I think I prefer the way it's handled in the first commit, especially since there might be a nice simplification there too.
crates/matrix-sdk-base/src/client.rs
Outdated
); | ||
|
||
let mut room_info = room.clone_info(); | ||
room_info.mark_as_invited(); |
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.
mark_as_knocked?
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.
let membership_event_content = invite_state.iter().find_map(|raw| { | ||
raw.deserialize().ok().iter().find_map(|e| { | ||
if let AnyStrippedStateEvent::RoomMember(membership_event) = e { | ||
if membership_event.sender == user_id { |
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.
Can you double-check this logic, please: I think the sender for an invite would not be the user themselves, but rather, the person who sent the invite. So we'd need to take a look at the state_key, in this case. (If that's true, consider adding a test which would have failed because of this?)
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.
Yes, I think this is an auto-completion typo 😬 . Nice catch!
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.
let user_id = self | ||
.session_meta() | ||
.expect("Sliding sync shouldn't run without an authenticated user.") | ||
.user_id | ||
.to_owned(); |
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.
Could we pass this user_id
as a parameter, to avoid repeating the work for each room?
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.
01b3bc9 should take care of this
// We need to find the membership event since it could be for either an invited | ||
// or knocked room | ||
let membership_event_content = invite_state.iter().find_map(|raw| { | ||
raw.deserialize().ok().iter().find_map(|e| { |
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.
So I'm not sure we're looking in the right place here: the required_state
events have already been deserialized and passed as a function parameter called state_events
. Might be worth checking against a real-world Synapse, but I'd expect the membership event to be there instead. If that's true, then we don't need the deserialization step here, and this solution feels better than the second one IMO (with the previous sync protocol, knocked rooms would appear in the knocked subset of the response, which is nice and simple — I'd rather not change the room state based on extra other information).
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.
Invite and Knock rooms use invite_state
instead of required_state
, I suspect their required_state would be empty, but I can double check.
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.
Yes, there's no required_state
for knocked rooms:
"!luXevcpKTZauFIpPnL:matrix.org": {
"bump_stamp": 21538303,
"notification_count": 0,
"highlight_count": 0,
"initial": true,
"invite_state": [
{
"content": {
"creator": "@jorgem_test:matrix.org",
"room_version": "7"
},
"sender": "@jorgem_test:matrix.org",
"state_key": "",
"type": "m.room.create"
},
{
"content": {
"join_rule": "knock"
},
"sender": "@jorgem_test:matrix.org",
"state_key": "",
"type": "m.room.join_rules"
},
{
"content": {
"name": "Knocking room test"
},
"sender": "@jorgem_test:matrix.org",
"state_key": "",
"type": "m.room.name"
},
{
"content": {
"algorithm": "m.megolm.v1.aes-sha2"
},
"sender": "@jorgem_test:matrix.org",
"state_key": "",
"type": "m.room.encryption"
},
{
"type": "m.room.member",
"state_key": "@jorgem:element.io",
"content": {
"avatar_url": "mxc://element.io/75d9a551895233d284aff390d2086814a2f7e875",
"displayname": "Jorge",
"membership": "knock"
},
"sender": "@jorgem:element.io"
}
]
}
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 option would be to handle the stripped state events in invite_state
as part of the membership in this same method, but I think that's not possible because we need the push_rules
too which are processed after this.
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.
We could also deserialize the stripped state events in process_sliding_sync_room
and pass it down both functions, this one and handle_invited_state
, so they'd be deserialized just once.
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 tried this approach ⬆️ in 0b1ef5b
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.
Some suggestions, all optional. Looks good to me.
@@ -527,30 +527,20 @@ impl BaseClient { | |||
pub(crate) async fn handle_invited_state( | |||
&self, | |||
room: &Room, | |||
events: &[Raw<AnyStrippedStateEvent>], | |||
events: &[(Raw<AnyStrippedStateEvent>, AnyStrippedStateEvent)], |
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.
Some documentation of the meaning of this parameter would be appreciated. It's a bit cryptic at the moment: a slice of pairs of things that look the same at first glance.
@@ -1042,6 +1090,76 @@ mod tests { | |||
assert_eq!(client_room.compute_display_name().await.unwrap().to_string(), "The Name"); | |||
} | |||
|
|||
#[async_test] | |||
async fn test_knocked_room_membership_event() { |
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.
test_receiving_a_knocked_room_membership_event_creates_a_knocked_room
?
} | ||
|
||
#[async_test] | ||
async fn test_knocked_room_membership_event_with_wrong_state_key() { |
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.
test_receiving_a_knocked_room_membership_event_with_wrong_state_key_creates_an_invited_room
?
} | ||
|
||
#[async_test] | ||
async fn test_unknown_room_membership_event_in_invite_state() { |
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.
test_receiving_an_unknown_room_membership_event_in_invite_state_creates_an_invited_room
?
687166e
to
59aaf22
Compare
Thanks for the feedback @andybalaam , I'll double check with @bnjbvr if these changes are what we want for the feature 🤞 . |
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.
Thanks, LGTM! only minor nits, so unless something big comes up, feel free to address these (or not) and merge. Good job!
crates/matrix-sdk-base/src/client.rs
Outdated
.filter_map(|raw_event| match raw_event.deserialize() { | ||
Ok(event) => Some((raw_event.clone(), event)), | ||
Err(e) => { | ||
warn!("Couldn't deserialize state event: {e}"); |
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.
warn!("Couldn't deserialize state event: {e}"); | |
warn!("Couldn't deserialize stripped state event: {e}"); |
Option<JoinedRoomUpdate>, | ||
Option<LeftRoomUpdate>, | ||
Option<InvitedRoom>, | ||
Option<KnockedRoom>, |
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.
(god what have we done here 😨)(no need to change anything right now, unless you see an obvious better way here)
@@ -428,7 +457,8 @@ impl BaseClient { | |||
|
|||
let push_rules = self.get_push_rules(account_data_processor).await?; | |||
|
|||
if let Some(invite_state) = &room_data.invite_state { | |||
// This will be used for both invited and knocked rooms |
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.
uber-nit:
// This will be used for both invited and knocked rooms | |
// This will be used for both invited and knocked rooms. |
state_events: &[AnySyncStateEvent], | ||
invite_state: &Option<Vec<(Raw<AnyStrippedStateEvent>, AnyStrippedStateEvent)>>, |
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.
nit: in Rust it's more idiomatic to pass Option<&T>
rather than &Option<T>
, by calling as_ref()
at the caller's call-site.
Alternatively, you could make this non Option
al and have the caller .unwrap_or_default()
.
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.
Could we name this stripped_state
, though, since it applies to both invites and knocked rooms?
"sender": "@alice:example.com", | ||
"type": "m.room.member", | ||
"state_key": "@bob:example.com", |
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.
Can someone knock on behalf of somebody else? 🤔 Should the sender/state_key be the same?
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.
Ooops. Copy&paste issue 😅 .
59aaf22
to
8636c3a
Compare
Changes
This PR contains 2 commits:
process_sliding_sync_room_membership
, deserializes them and decides whether the resulting room should be a knock or invite one default to invite if not sure. Then it propagates the changes up the flow.handle_stripped_state
to parse the contents of theinvite_state
stripped state events it seemed better to reuse this and deserialize the events only once, then mark the room as invited or knocked in this method. Ideally this should be part of the innerfn BaseRoomInfo::handle_stripped_state_event
, but that doesn't have access to theRoom::state
property.Both solutions work AFAICT, the 1st one centralises the membership processing in a single point but it's more inefficient, the 2nd one does only one round of deserialization but hides the membership change a bit lower in the sliding sync processing flow. Let me know if you have any preferences and I'll use one of those versions, or propose a better alternative.
Existing tests have been extended to check the invite vs knock room state processing.
Signed-off-by: