use ruma::{
EventId, OwnedUserId, UserId,
events::{
AnySyncMessageLikeEvent, AnySyncTimelineEvent,
rtc::decline::{RtcDeclineEventContent, SyncRtcDeclineEvent},
},
};
use thiserror::Error;
use tokio::sync::broadcast;
use tracing::instrument;
use crate::{Room, event_handler::EventHandlerDropGuard, room::EventSource};
#[derive(Debug, Error)]
pub enum CallError {
#[error("Couldn't fetch the remote event: {0}")]
Fetch(Box<crate::Error>),
#[error("You cannot decline this event type.")]
BadEventType,
#[error("You cannot decline your own call.")]
DeclineOwnCall,
#[error(transparent)]
Deserialize(#[from] serde_json::Error),
}
impl Room {
#[instrument(skip(self), fields(room = %self.room_id()))]
pub async fn make_decline_call_event(
&self,
notification_event_id: &EventId,
) -> Result<RtcDeclineEventContent, CallError> {
make_call_decline_event(self, self.own_user_id(), notification_event_id).await
}
pub fn subscribe_to_call_decline_events(
&self,
notification_event_id: &EventId,
) -> (EventHandlerDropGuard, broadcast::Receiver<OwnedUserId>) {
let (sender, receiver) = broadcast::channel(16);
let decline_call_event_handler_handle =
self.client.add_room_event_handler(self.room_id(), {
let own_notification_event_id = notification_event_id.to_owned();
move |event: SyncRtcDeclineEvent| async move {
if let Some(declined_event_id) =
event.as_original().map(|ev| ev.content.relates_to.event_id.clone())
&& declined_event_id == own_notification_event_id
{
let _ = sender.send(event.sender().to_owned());
}
}
});
let drop_guard = self.client().event_handler_drop_guard(decline_call_event_handler_handle);
(drop_guard, receiver)
}
}
async fn make_call_decline_event(
room: &Room,
own_user_id: &UserId,
notification_event_id: &EventId,
) -> Result<RtcDeclineEventContent, CallError> {
let target = room
.get_event(notification_event_id)
.await
.map_err(|err| CallError::Fetch(Box::new(err)))?;
let event = target.raw().deserialize().map_err(CallError::Deserialize)?;
if let AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RtcNotification(notify)) =
event
{
if notify.sender() == own_user_id {
Err(CallError::DeclineOwnCall)
} else {
Ok(RtcDeclineEventContent::new(notification_event_id))
}
} else {
Err(CallError::BadEventType)
}
}