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-ui: Add TimelineFocus::PinnedEvents #3773

Merged
merged 5 commits into from
Aug 2, 2024

Conversation

jmartinesp
Copy link
Contributor

@jmartinesp jmartinesp commented Jul 29, 2024

Changes

  • Create a new type of TimelineFocus, TimelineFocus::PinnedEvents that will use the pinned event ids in RoomInfo to load the associated events, cache them and sort them chronologically.

  • Create PinnedEventsRoom trait to be able to provide the necessary data to the new timeline type.

  • Change the is_live parameter used in the Timeline code for a LiveTimelineUpdatesAllowed enum to distinguish between timelines that need to process every update (live timeline), those who don't need to process any (the focused one) and those which may need to process some items (pinned events one).

  • Add tests and a benchmark for the concurrent pinned event loading.

  • Public API changes documented in changelogs (optional)

Signed-off-by:

@jmartinesp jmartinesp force-pushed the jme/feat/focused-pinned-events-timeline branch from ba74a50 to dae69d2 Compare August 1, 2024 13:16
@jmartinesp jmartinesp changed the title WIP: Add PinnedEvents focus for the timeline sdk-ui: Add TimelineFocus::PinnedEvents Aug 1, 2024
@jmartinesp jmartinesp marked this pull request as ready for review August 1, 2024 13:32
@jmartinesp jmartinesp requested a review from a team as a code owner August 1, 2024 13:32
@jmartinesp jmartinesp requested review from andybalaam and removed request for a team August 1, 2024 13:32
Copy link

codecov bot commented Aug 1, 2024

Codecov Report

Attention: Patch coverage is 87.97468% with 19 lines in your changes missing coverage. Please review.

Project coverage is 84.04%. Comparing base (21efd60) to head (4b33508).
Report is 1 commits behind head on main.

Files Patch % Lines
benchmarks/benches/room_bench.rs 0.00% 11 Missing ⚠️
crates/matrix-sdk-ui/src/timeline/inner/mod.rs 85.71% 5 Missing ⚠️
...matrix-sdk-ui/src/timeline/pinned_events_loader.rs 96.49% 2 Missing ⚠️
crates/matrix-sdk-ui/src/timeline/event_handler.rs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3773      +/-   ##
==========================================
+ Coverage   84.03%   84.04%   +0.01%     
==========================================
  Files         259      261       +2     
  Lines       27202    27334     +132     
==========================================
+ Hits        22859    22974     +115     
- Misses       4343     4360      +17     

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

Copy link
Member

@andybalaam andybalaam left a comment

Choose a reason for hiding this comment

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

Looks good! Some questions.

@@ -175,6 +176,27 @@ impl TimelineBuilder {
let room = inner.room();
let client = room.client();

let mut pinned_event_ids_stream = room.pinned_event_ids_stream();
Copy link
Member

Choose a reason for hiding this comment

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

Can this line move inside the if?

match origin {
EventsOrigin::Sync => RemoteEventOrigin::Sync,
// Special case for pinned events: when we receive new events what we'll do is
// updated the cache for those events that are pinned and reload the
Copy link
Member

Choose a reason for hiding this comment

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

updated -> update

// updated the cache for those events that are pinned and reload the
// list.
match &*focus.clone() {
TimelineFocus::PinnedEvents { .. } => {
Copy link
Member

Choose a reason for hiding this comment

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

So we ignore the events that appeared via AddTimelineEvents and just refresh the whole list? Might be good to make this clear in the comment as I didn't quite get 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.

Ok, I'll try to come up with a better comment to explain this.

// Special case for pinned events: when we receive new events what we'll do is
// updated the cache for those events that are pinned and reload the
// list.
match &*focus.clone() {
Copy link
Member

Choose a reason for hiding this comment

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

If you can, I would prefer an if let here instead of match, because the pinned case is currently making the normal case hard to see.

}

if !event_ids_to_request.is_empty() {
let semaphore = Arc::new(Semaphore::new(self.max_concurrent_requests));
Copy link
Member

Choose a reason for hiding this comment

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

Can you extract the logic for performing-things-concurrently-with-a-limit into a separate function, and then pass in the list of inputs (event IDs) and a closure for the thing to do? Don't worry if not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems like I can't because I'd have to make the closure async and that's unstable.

Copy link
Member

Choose a reason for hiding this comment

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

Normally when you want an async closure you can get away with a closure that returns a Future by doing:

|args| async { body }

Not sure 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 think I'll try doing this in a separate PR, since the team implementing the feature is a bit blocked without it merged.

Copy link
Member

Choose a reason for hiding this comment

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

Yep, fine - thanks.

fn room_pinned_event_ids(&self) -> Vec<OwnedEventId>;

/// Checks whether an event id is pinned in this room.
fn room_is_pinned_event_id(&self, event_id: &EventId) -> bool;
Copy link
Member

Choose a reason for hiding this comment

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

I think just is_pinned_event_id or is_pinned_event, or even is_pinned.

Copy link
Member

Choose a reason for hiding this comment

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

(Basically I think room is not helpful 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.

The problem with these is there already are some existing methods in Room that have these names and they access private properties, and then I had to create new methods to expose them in the PinnedEventsRoom trait and use them in this file.

I can't just replace the existing methods because they need access to those private properties to work and they can't have the same name because the compiler will mix them up. Unless there's some way to distinguish between those?

A good example of this is PinnedEventsRoom::room_pinned_event_ids and Room::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.

Ok, I think I got it with 237ee9a.

Copy link
Member

Choose a reason for hiding this comment

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

Looks good.

async fn room_event(&self, event_id: &EventId) -> Result<SyncTimelineEvent, PaginatorError>;

/// Get the pinned event ids for a room.
fn room_pinned_event_ids(&self) -> 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 suggest 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.

Same as above, 237ee9a.


runtime.block_on(
Mock::given(method("GET"))
.and(path_regex(r"/_matrix/client/r0/rooms/.*/event/.*"))
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to make the mocked response slow? If so I think it would be helpful, to demonstrate that we are fast because we wait for the responses in parallel.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The mocked response already has a delay of 50ms. When tested agains the sequential approach, the concurrent one was 0.55s vs 5.3s.

Copy link
Member

Choose a reason for hiding this comment

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

Perfect, thanks!

… stream and checking whether an event is pinned in the room or not
…nedEvents` to load the live pinned events for a room.

 Add `PinnedEventsLoader` to encapsulate this logic, being able to provide a max number of events to load and how many can be loaded at the same time. Also implement an event cache for it.

 Add `PinnedEventsRoom` trait to use it in the same way as `PaginableRoom`, only for pinned events.
@jmartinesp jmartinesp force-pushed the jme/feat/focused-pinned-events-timeline branch from 237ee9a to 4b33508 Compare August 2, 2024 10:48
@jmartinesp jmartinesp enabled auto-merge (rebase) August 2, 2024 10:51
@jmartinesp jmartinesp merged commit 1ca4377 into main Aug 2, 2024
40 checks passed
@jmartinesp jmartinesp deleted the jme/feat/focused-pinned-events-timeline branch August 2, 2024 11:11
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