use std::sync::Arc;
use rvoip_sip_core::types::Method;
use crate::api::handle::CallId;
use crate::api::headers::{take_staged, BuilderHeaderState, SipRequestOptions};
use crate::api::unified::UnifiedCoordinator;
use crate::errors::{Result, SessionError};
use crate::session_registry::SessionRegistryHandle;
use rvoip_sip_core::types::headers::{HeaderName, HeaderValue, TypedHeader};
pub struct ProvisionalBuilder {
coord: Arc<UnifiedCoordinator>,
call_id: CallId,
lifecycle_handle: Option<SessionRegistryHandle>,
code: u16,
sdp: Option<String>,
require_100rel: bool,
state: BuilderHeaderState,
}
impl ProvisionalBuilder {
pub(crate) fn new(coord: Arc<UnifiedCoordinator>, call_id: CallId, code: u16) -> Self {
let lifecycle_handle = coord.helpers.state_machine.store.lifecycle_handle(&call_id);
Self::new_captured(coord, call_id, lifecycle_handle, code)
}
pub(crate) fn new_captured(
coord: Arc<UnifiedCoordinator>,
call_id: CallId,
lifecycle_handle: Option<SessionRegistryHandle>,
code: u16,
) -> Self {
Self {
coord,
call_id,
lifecycle_handle,
code,
sdp: None,
require_100rel: false,
state: BuilderHeaderState::default(),
}
}
pub fn with_sdp(mut self, sdp: impl Into<String>) -> Self {
self.sdp = Some(sdp.into());
self
}
pub fn with_require_100rel(mut self, require: bool) -> Self {
self.require_100rel = require;
self
}
pub async fn send(mut self) -> Result<()> {
let lifecycle_handle = self
.lifecycle_handle
.as_ref()
.ok_or_else(|| SessionError::SessionNotFound(self.call_id.to_string()))?;
let mut extras = take_staged(&mut self.state);
if self.require_100rel {
extras.push(TypedHeader::Other(
HeaderName::Require,
HeaderValue::Raw(b"100rel".to_vec()),
));
}
if extras.is_empty()
&& (self.code == 183 || self.code == 180)
&& !self
.coord
.dialog_adapter()
.peer_supports_100rel(&self.call_id)
.await?
{
return Err(crate::errors::SessionError::UnreliableProvisionalsNotSupported);
}
self.coord
.helpers
.send_provisional_with_response(
&self.call_id,
lifecycle_handle,
self.code,
self.sdp,
extras,
)
.await
}
}
impl SipRequestOptions for ProvisionalBuilder {
fn method(&self) -> Method {
Method::Invite
}
fn header_state_mut(&mut self) -> &mut BuilderHeaderState {
&mut self.state
}
fn header_state(&self) -> &BuilderHeaderState {
&self.state
}
}