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;
pub struct ReferBuilder {
coord: Arc<UnifiedCoordinator>,
session_id: CallId,
refer_to: String,
replaces: Option<String>,
referred_by: Option<String>,
target_dialog: Option<String>,
state: BuilderHeaderState,
}
impl ReferBuilder {
pub(crate) fn new(
coord: Arc<UnifiedCoordinator>,
session_id: CallId,
refer_to: impl Into<String>,
) -> Self {
Self {
coord,
session_id,
refer_to: refer_to.into(),
replaces: None,
referred_by: None,
target_dialog: None,
state: BuilderHeaderState::default(),
}
}
pub fn with_replaces(mut self, replaces: impl Into<String>) -> Self {
self.replaces = Some(replaces.into());
self
}
pub fn with_referred_by(mut self, uri: impl Into<String>) -> Self {
self.referred_by = Some(uri.into());
self
}
pub fn with_target_dialog(mut self, request: &crate::api::incoming::IncomingRequest) -> Self {
if let Some(req) = request.raw_request() {
if let Some(cid) = req.call_id() {
let mut value = cid.to_string();
if let Some(tag) = req.from().and_then(|f| f.tag()) {
value.push_str(";local-tag=");
value.push_str(tag);
}
if let Some(tag) = req.to().and_then(|t| t.tag()) {
value.push_str(";remote-tag=");
value.push_str(tag);
}
self.target_dialog = Some(value);
}
}
self
}
pub async fn send(mut self) -> Result<()> {
let extra_headers = take_staged(&mut self.state);
let opts = Arc::new(rvoip_sip_dialog::api::unified::ReferRequestOptions {
refer_to: self.refer_to,
replaces: self.replaces,
referred_by: self.referred_by,
target_dialog: self.target_dialog,
extra_headers,
});
self.coord
.stage_outbound_options(
&self.session_id,
crate::state_machine::executor::PendingOptionsSlot::Refer(opts),
)
.await?;
self.coord
.dispatch_outbound(
&self.session_id,
crate::state_table::EventType::SendOutboundRefer,
)
.await?;
Ok(())
}
}
impl SipRequestOptions for ReferBuilder {
fn method(&self) -> Method {
Method::Refer
}
fn header_state_mut(&mut self) -> &mut BuilderHeaderState {
&mut self.state
}
fn header_state(&self) -> &BuilderHeaderState {
&self.state
}
}