Skip to content
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

sdk-base: add Room::pinned_events(&self) #3747

Merged
merged 1 commit into from
Jul 23, 2024

Conversation

jmartinesp
Copy link
Contributor

@jmartinesp jmartinesp commented Jul 22, 2024

This can be used to subscribe to pinned event ids in a room.

Implements the first part of #3726.

  • Public API changes documented in changelogs (optional)

Signed-off-by:

@jmartinesp jmartinesp requested a review from a team as a code owner July 22, 2024 10:22
@jmartinesp jmartinesp requested review from bnjbvr and removed request for a team July 22, 2024 10:22
@jmartinesp jmartinesp force-pushed the jme/feat/reactive-pinned-events branch from b08d07f to 1750b00 Compare July 22, 2024 12:11
Copy link

codecov bot commented Jul 22, 2024

Codecov Report

Attention: Patch coverage is 62.50000% with 3 lines in your changes missing coverage. Please review.

Project coverage is 84.02%. Comparing base (99da0ff) to head (3e78ee7).

Files Patch % Lines
crates/matrix-sdk-base/src/rooms/mod.rs 40.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3747      +/-   ##
==========================================
- Coverage   84.02%   84.02%   -0.01%     
==========================================
  Files         260      260              
  Lines       26729    26737       +8     
==========================================
+ Hits        22459    22465       +6     
- Misses       4270     4272       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like you're on the right track! Thanks for writing a test.

@@ -340,6 +340,9 @@ pub struct StateChanges {
/// A map from room id to a map of a display name and a set of user ids that
/// share that display name in the given room.
pub ambiguity_maps: BTreeMap<OwnedRoomId, BTreeMap<String, BTreeSet<OwnedUserId>>>,

/// A map of `RoomId` to pinned `OwnedEventId`s for each room.
pub pinned_events: BTreeMap<OwnedRoomId, Vec<OwnedEventId>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be here: this is not stored, and this struct is meant to include things that are to be stored. Instead, you probably want a local variable in the one function that makes use of this pinned_events field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this in eafed32


/// The list of pinned event ids in this room in an observable format so
/// they can be subscribed to.
pub pinned_event_ids: SharedObservable<Vec<OwnedEventId>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not pub, since there's a getter for a subscriber

Also, would it make sense to use ObservableVector here? If we did that, and rejigger the API so that we only push new pinned event / remove pinned event, we could have a finer-grained API, but maybe it's not worth it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try 🤞 .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ObservableVector doesn't implement Clone so it can't be used in Room, which does.

if let Some(room) = self.store.room(&room_id) {
room.pinned_event_ids.update(|ids| {
ids.clear();
ids.append(&mut pinned_event_ids.clone());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦀 🧑‍🏫

  • Vec::extend can take an iterator of the element type (that's ids)
  • and a Vec also has an IntoIter implementation, so it can be used as the parameter for extend (here I'm talking about pinned_event_ids).

Combining the two, that gives you a way to avoid the cloning:

Suggested change
ids.append(&mut pinned_event_ids.clone());
ids.extend(pinned_event_ids);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to use Vector::extend_from_slice in some places instead, but it's done in 8c43c75

@@ -1173,6 +1180,15 @@ impl BaseClient {
}
}

for (room_id, pinned_event_ids) in changes.pinned_events.clone() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you shouldn't need the clone() here, and as said before changes.pinned_events should be a local variable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 8c43c75

@jmartinesp jmartinesp force-pushed the jme/feat/reactive-pinned-events branch 2 times, most recently from 8c43c75 to 0d76899 Compare July 22, 2024 14:56
@jmartinesp jmartinesp requested a review from bnjbvr July 22, 2024 14:56
@jmartinesp
Copy link
Contributor Author

I had to add an extra check so the pinned event ids are only emitted if they are different from the previous list.

@bnjbvr
Copy link
Member

bnjbvr commented Jul 22, 2024

I had to add an extra check so the pinned event ids are only emitted if they are different from the previous list.

Sweet, did you add a test for that too? 🥺

@jmartinesp
Copy link
Contributor Author

I had to add an extra check so the pinned event ids are only emitted if they are different from the previous list.

Sweet, did you add a test for that too? 🥺

The test for this is the previously added one not failing anymore 😅 .

@jmartinesp
Copy link
Contributor Author

I actually ended up adding an extra test check and improving how the new values are set.

Comment on lines 136 to 138
/// The list of pinned event ids in this room in an observable format so
/// they can be subscribed to.
pub(crate) pinned_event_ids: SharedObservable<Vec<OwnedEventId>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the reason why we usually don't put things in this struct is that they're not persisted after a reload; if you reload a room, you'd have to wait for the next sync to arrive to give you the list of events, and if you happen to be offline, that means that now you don't have access to pinned events.

From here, we have a few possibilities:

  • include the Vec<OwnedEventId> in RoomInfo,
  • include the pinned event in the BaseRoomInfo, and have a getter to read the pinned event ids from there
  • have a new (de)serializable field in Room that is filled at startup, and updated as the events come. You've done half of the work here by having it be updated as the events come, and we'd need some way to serialize/deserialize it too later.

My preference would likely go to the first or second option (second option might be faster to ser/de), to benefit from persistence. Can you also add a test that would've failed without this change, please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I tried fixing this in 4aa51ca using the 2nd strategy 🤞 .

Comment on lines +262 to +266
AnyStrippedStateEvent::RoomPinnedEvents(p) => {
if let Some(pinned) = p.content.pinned.clone() {
self.pinned_events = Some(RoomPinnedEventsEventContent::new(pinned));
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure about this part.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stripped events = for a room in which we're invited. I think your code is fine, we could also decide to store None there, but this shouldn't matter much 👍 I don't expect one to be able to look at pinned events in an invited room, at least for a first pass.

@jmartinesp jmartinesp requested a review from bnjbvr July 23, 2024 12:53
Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines +262 to +266
AnyStrippedStateEvent::RoomPinnedEvents(p) => {
if let Some(pinned) = p.content.pinned.clone() {
self.pinned_events = Some(RoomPinnedEventsEventContent::new(pinned));
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stripped events = for a room in which we're invited. I think your code is fine, we could also decide to store None there, but this shouldn't matter much 👍 I don't expect one to be able to look at pinned events in an invited room, at least for a first pass.

@@ -117,6 +118,8 @@ pub struct BaseRoomInfo {
/// others, and this field collects them.
#[serde(skip_serializing_if = "RoomNotableTags::is_empty", default)]
pub(crate) notable_tags: RoomNotableTags,
/// The `m.room.pinned_events` of this room.
pub(crate) pinned_events: Option<RoomPinnedEventsEventContent>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: i think we could have used MinimalStateEvent here, but it's unclear what's the value of it, so no need to change anything here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try changing it so it matches the other fields if it's easy to do (I'm not sure how I missed it 🫤 ).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it does make everything way more complex just to store a possible event id which isn't used anywhere, so it's probably not worth to add it.

Also add `Room::pinned_events(&self)` to get the current pinned events at any time.
@jmartinesp jmartinesp force-pushed the jme/feat/reactive-pinned-events branch from 4aa51ca to 3e78ee7 Compare July 23, 2024 15:03
@jmartinesp jmartinesp enabled auto-merge (rebase) July 23, 2024 15:07
@jmartinesp jmartinesp merged commit 79010af into main Jul 23, 2024
40 checks passed
@jmartinesp jmartinesp deleted the jme/feat/reactive-pinned-events branch July 23, 2024 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants