Skip to content

Rework live location shares stream#6385

Open
ganfra wants to merge 14 commits intomainfrom
ganfra/live_location_shares_stream
Open

Rework live location shares stream#6385
ganfra wants to merge 14 commits intomainfrom
ganfra/live_location_shares_stream

Conversation

@ganfra
Copy link
Copy Markdown
Contributor

@ganfra ganfra commented Mar 31, 2026

Motivation

The previous observe_live_location_shares API was limited: it emitted individual beacon events one at a time, excluded the own user's shares, provided beacon_info only as an Option (requiring a state fetch per
event), and had no awareness of share start/stop lifecycle.

What changed

New stream semantics (matrix-sdk)

Room::observe_live_location_shares is replaced by Room::subscribe_to_live_location_shares. The new method returns a Stream<Item = Vec> that always emits the full snapshot of currently active
shares:

  • Seeded from the event cache: on subscription, the stream immediately emits the current active shares loaded from cached beacon events.
  • Includes own user: own shares are no longer filtered out.
  • Handles lifecycle: a beacon_info state event with live: false removes the user from the active list and triggers a stream update.
  • Fast path for tracked users: when a new beacon arrives for a user already in the map, their cached beacon_info is reused instead of re-fetching from the state store.
  • Bug fix: a beacon event for a user with a non-live beacon_info no longer incorrectly triggers a stream update.
  • beacon_info on LiveLocationShare is now BeaconInfoEventContent (non-optional).

FFI bindings (matrix-sdk-ffi)

Room::observe_live_location_shares is similarly replaced by Room::subscribe_to_live_location_shares, which takes a LiveLocationShareListener callback (new interface) called with the full updated
Vec on every change.

  • I've documented the public API Changes in the appropriate CHANGELOG.md files.
  • This PR was made with the help of AI.

Signed-off-by:

@ganfra ganfra requested a review from a team as a code owner March 31, 2026 15:08
@ganfra ganfra requested review from bnjbvr and stefanceriu and removed request for a team March 31, 2026 15:08
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 31, 2026

Merging this PR will not alter performance

✅ 50 untouched benchmarks


Comparing ganfra/live_location_shares_stream (074eec7) with main (a65fec3)

Open in CodSpeed

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 79.36508% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.85%. Comparing base (a65fec3) to head (074eec7).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
crates/matrix-sdk/src/live_location_share.rs 80.53% 13 Missing and 9 partials ⚠️
crates/matrix-sdk/src/room/mod.rs 69.23% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6385      +/-   ##
==========================================
- Coverage   89.87%   89.85%   -0.03%     
==========================================
  Files         378      378              
  Lines      103445   103552     +107     
  Branches   103445   103552     +107     
==========================================
+ Hits        92973    93047      +74     
- Misses       6902     6922      +20     
- Partials     3570     3583      +13     

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

@ganfra ganfra force-pushed the ganfra/live_location_shares_stream branch from fb8bd4d to 2cf6859 Compare April 1, 2026 06:48
@bnjbvr bnjbvr removed their request for review April 1, 2026 08:50
Comment on lines +105 to +109
const DEFAULT_ROOM_SUBSCRIPTION_EXTRA_REQUIRED_STATE: &[(StateEventType, &str)] =
&[(StateEventType::RoomPinnedEvents, "")];
const DEFAULT_ROOM_SUBSCRIPTION_EXTRA_REQUIRED_STATE: &[(StateEventType, &str)] = &[
(StateEventType::RoomPinnedEvents, ""),
];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This feels unnecessary, ai? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah I think I had first added the beacon_info to this list instead

Comment on lines +70 to +72
pub struct LiveLocationShares;

impl LiveLocationShares {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think I would've preferred it if this service would work on top of the ObservableVector and setup its observers in the constructor, similar to all the other list based services we're building, for consistency.

A lot of these services live on the UI crate level but room_directory_search makes use of it on the sdk crate level.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought we said we didn't want ObservableVector for such api? But happy to change if you think it's better.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah, I see what caused the confusing: I though you were asking if we should bother tracking atomic updates and I thought it's fine, we can just reload the whole list every time. All while still using ObservableVector e.g. space filters

space_state.space_filters.clear();
space_state.space_filters.append(new_filters);

I think it would be great if you can change it so the handlers, the helpers and everything else is contained withing this LiveLocationShares service 🙏

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok I see! I've been using Stream api as it's also used in other places in the sdk.

Comment on lines +4031 to +4041
/// Get all currently active live location shares in the room.
///
/// Returns a list of all users who are currently sharing their live
/// location (excluding the current user), along with their latest known
/// location if available in the event cache.
pub async fn get_active_live_location_shares(
&self,
) -> Result<Vec<LiveLocationShare>> {
crate::live_location_share::get_active_live_location_shares(self).await
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would expected all usages to go through LiveLocationShares, not bypass that whole layer. (See my other comment about ObservableVector)

@ganfra ganfra force-pushed the ganfra/live_location_shares_stream branch from 7baa551 to 1ab091a Compare April 2, 2026 15:33
@ganfra ganfra requested a review from stefanceriu April 3, 2026 16:01
@ganfra
Copy link
Copy Markdown
Contributor Author

ganfra commented Apr 3, 2026

Ok @stefanceriu the PR is ready to re-review I think :D

Copy link
Copy Markdown
Member

@stefanceriu stefanceriu left a comment

Choose a reason for hiding this comment

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

This is looking great, just a couple of small comments!

I'll be out for a bit so I'm going to let the review gods choose somebody else to help you out with a merge (squash 🙏 ) next week 🚀.

/// The listener is called immediately with the current list of shares as a
/// `Reset` update, then called again with incremental updates whenever the
/// list changes (location updates, shares starting/stopping).
pub async fn subscribe_to_live_location_shares(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this just return the LiveLocationShares "service" so the final user can do whatever they need with it? (similar to the ThreadListService, SpaceService etc.?

user_id: event.user_id.to_string(),
}])
// Keep live_location_shares alive to preserve event handlers.
let _live_location_shares = live_location_shares;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's probably best we let the final user worry about lifetimes.

pub location: LocationContent,
/// A timestamp in milliseconds since Unix Epoch on that day in local
/// time.
/// A timestamp in milliseconds since Unix Epoch on that day in local time.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is actually origin_server_ts as far as I can tell so not sure what local times means.

///
/// Returns an error if the event is redacted, stripped, not found or could
/// not be deserialized.
pub(crate) async fn get_user_beacon_info(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if we should just fold this into LiveLocationShares now 🤔

pub beacon_info: Option<BeaconInfoEventContent>,
/// The user ID of the person sharing their live location.
pub user_id: OwnedUserId,
/// The user's last known location, if any beacon has been received.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Techincally the "asset"'s location

@stefanceriu stefanceriu requested review from a team and bnjbvr and removed request for a team April 4, 2026 18:53
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