use crate::api::dialog_package::DialogInfo;
use crate::api::events::Event;
use crate::api::send::subscribe::SubscriptionHandle;
use crate::api::stream_peer::EventReceiver;
use crate::api::unified::UnifiedCoordinator;
use crate::errors::{Result, SessionError};
use crate::state_table::types::SessionId;
use std::sync::Arc;
use std::time::Duration;
#[derive(Clone)]
pub struct DialogSubscriptionHandle {
subscription_id: SessionId,
target_uri: String,
coordinator: Arc<UnifiedCoordinator>,
}
impl DialogSubscriptionHandle {
pub(crate) fn from_subscription(
subscription: SubscriptionHandle,
target_uri: String,
) -> Result<Self> {
let coordinator = subscription.coord.clone().ok_or_else(|| {
SessionError::InternalError(
"DialogSubscriptionHandle: subscription handle is detached \
(no coordinator)"
.to_string(),
)
})?;
let session_id = subscription.session_id.clone().ok_or_else(|| {
SessionError::InternalError(
"DialogSubscriptionHandle: subscription handle has no session id".to_string(),
)
})?;
Ok(Self {
subscription_id: session_id,
target_uri,
coordinator,
})
}
pub fn id(&self) -> &SessionId {
&self.subscription_id
}
pub fn target_uri(&self) -> &str {
&self.target_uri
}
pub async fn events(&self) -> Result<EventReceiver> {
self.coordinator
.events_for_session(&self.subscription_id)
.await
}
pub async fn wait_for_dialog<F>(
&self,
mut predicate: F,
timeout: Option<Duration>,
) -> Result<DialogInfo>
where
F: FnMut(&DialogInfo) -> bool,
{
let mut events = self.events().await?;
let fut = async {
loop {
match events.next().await {
Some(Event::DialogPackageNotify { dialogs, .. }) => {
if let Some(dialog) = dialogs.into_iter().find(|d| predicate(d)) {
return Ok(dialog);
}
}
Some(Event::DialogStateChanged { dialog, .. }) if predicate(&dialog) => {
return Ok(dialog);
}
Some(_) => {}
None => {
return Err(SessionError::Other(
"Event channel closed while waiting for dialog package event"
.to_string(),
))
}
}
}
};
match timeout {
Some(duration) => tokio::time::timeout(duration, fut)
.await
.map_err(|_| SessionError::Timeout("wait_for_dialog timed out".to_string()))?,
None => fut.await,
}
}
pub async fn unsubscribe(&self) -> Result<()> {
self.coordinator
.dialog_adapter()
.send_subscribe_oob_with_options(
&self.target_uri,
rvoip_sip_dialog::api::unified::SubscribeRequestOptions {
event: "dialog".to_string(),
expires: 0,
refresh: false,
..Default::default()
},
)
.await?;
Ok(())
}
}