Skip to content

Commit

Permalink
feat(sdk): support for listening to beacon events
Browse files Browse the repository at this point in the history
  • Loading branch information
torrybr committed Nov 15, 2024
1 parent cefd5a2 commit 05c1172
Show file tree
Hide file tree
Showing 4 changed files with 379 additions and 7 deletions.
1 change: 1 addition & 0 deletions crates/matrix-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub use sliding_sync::{
#[cfg(feature = "uniffi")]
uniffi::setup_scaffolding!();

mod live_location_share;
#[cfg(any(test, feature = "testing"))]
pub mod test_utils;

Expand Down
40 changes: 40 additions & 0 deletions crates/matrix-sdk/src/live_location_share.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2024 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Types for live location sharing.

use ruma::{
events::{beacon_info::BeaconInfoEventContent, location::LocationContent},
MilliSecondsSinceUnixEpoch, OwnedUserId,
};

/// Details of the last known location beacon.
#[derive(Clone, Debug)]
pub struct LastLocation {
/// The most recent location content of the user.
pub location: LocationContent,
/// The timestamp of when the location was updated.
pub ts: MilliSecondsSinceUnixEpoch,
}

/// Details of a users live location share.
#[derive(Clone, Debug)]
pub struct LiveLocationShare {
/// The user's last known location.
pub last_location: LastLocation,
/// Information about the associated beacon event.
pub beacon_info: BeaconInfoEventContent,
/// The user ID of the person sharing their live location.
pub user_id: OwnedUserId,
}
53 changes: 48 additions & 5 deletions crates/matrix-sdk/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ use ruma::{
},
assign,
events::{
beacon::BeaconEventContent,
beacon::{BeaconEventContent, OriginalSyncBeaconEvent},
beacon_info::BeaconInfoEventContent,
call::notify::{ApplicationType, CallNotifyEventContent, NotifyType},
direct::DirectEventContent,
Expand Down Expand Up @@ -132,6 +132,7 @@ use crate::{
error::{BeaconError, WrongRoomState},
event_cache::{self, EventCacheDropHandles, RoomEventCache},
event_handler::{EventHandler, EventHandlerDropGuard, EventHandlerHandle, SyncEvent},
live_location_share::{LastLocation, LiveLocationShare},
media::{MediaFormat, MediaRequestParameters},
notification_settings::{IsEncrypted, IsOneToOne, RoomNotificationMode},
room::power_levels::{RoomPowerLevelChanges, RoomPowerLevelsExt},
Expand Down Expand Up @@ -2990,17 +2991,18 @@ impl Room {
Ok(())
}

/// Get the beacon information event in the room for the current user.
/// Get the beacon information event in the room for the `user_id`.
///
/// # Errors
///
/// Returns an error if the event is redacted, stripped, not found or could
/// not be deserialized.
async fn get_user_beacon_info(
&self,
user_id: &UserId,
) -> Result<OriginalSyncStateEvent<BeaconInfoEventContent>, BeaconError> {
let raw_event = self
.get_state_event_static_for_key::<BeaconInfoEventContent, _>(self.own_user_id())
.get_state_event_static_for_key::<BeaconInfoEventContent, _>(user_id)
.await?
.ok_or(BeaconError::NotFound)?;

Expand Down Expand Up @@ -3053,7 +3055,7 @@ impl Room {
) -> Result<send_state_event::v3::Response, BeaconError> {
self.ensure_room_joined()?;

let mut beacon_info_event = self.get_user_beacon_info().await?;
let mut beacon_info_event = self.get_user_beacon_info(self.own_user_id()).await?;
beacon_info_event.content.stop();
Ok(self.send_state_event_for_key(self.own_user_id(), beacon_info_event.content).await?)
}
Expand All @@ -3075,7 +3077,7 @@ impl Room {
) -> Result<send_message_event::v3::Response, BeaconError> {
self.ensure_room_joined()?;

let beacon_info_event = self.get_user_beacon_info().await?;
let beacon_info_event = self.get_user_beacon_info(self.own_user_id()).await?;

if beacon_info_event.content.is_live() {
let content = BeaconEventContent::new(beacon_info_event.event_id, geo_uri, None);
Expand Down Expand Up @@ -3166,6 +3168,47 @@ impl Room {
},
}
}

/// Subscribe to live location sharing events for this room.
///
/// The returned receiver will receive a new event for each sync response
/// that contains a `m.beacon` event.
pub fn subscribe_to_live_location_shares(
&self,
) -> (EventHandlerDropGuard, broadcast::Receiver<LiveLocationShare>) {
let (sender, receiver) = broadcast::channel(128);

let room_id = self.room_id().to_owned();
let room = self.clone();

let beacon_event_handler_handle = self.client.add_room_event_handler(&room_id, {
move |event: OriginalSyncBeaconEvent| async move {
let user_id = event.sender;

let beacon_info = match room.get_user_beacon_info(&user_id).await {
Ok(info) => info.content,
Err(e) => {
eprintln!("Failed to get beacon info: {:?}", e);
return;
}
};

let live_location_share = LiveLocationShare {
last_location: LastLocation {
location: event.content.location,
ts: event.content.ts,
},
user_id,
beacon_info,
};

let _ = sender.send(live_location_share);
}
});

let drop_guard = self.client().event_handler_drop_guard(beacon_event_handler_handle);
(drop_guard, receiver)
}
}

#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
Expand Down
Loading

0 comments on commit 05c1172

Please sign in to comment.