use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use crate::client::{SippCancellationHandle, SippCancellationReason, SippRequestContext};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GatewayCancellationReason {
ClientDisconnected,
ServerShutdown,
CallerCancelled,
DeadlineExceeded,
}
impl GatewayCancellationReason {
const fn into_client(self) -> SippCancellationReason {
match self {
Self::ClientDisconnected => SippCancellationReason::ClientDisconnected,
Self::ServerShutdown => SippCancellationReason::ServerShutdown,
Self::CallerCancelled => SippCancellationReason::CallerCancelled,
Self::DeadlineExceeded => SippCancellationReason::DeadlineExceeded,
}
}
}
#[derive(Default)]
struct CancellationState {
reason: Option<GatewayCancellationReason>,
runs: Vec<SippCancellationHandle>,
}
#[derive(Clone, Default)]
pub struct GatewayCancellation {
state: Arc<Mutex<CancellationState>>,
}
impl GatewayCancellation {
pub fn cancel(&self, reason: GatewayCancellationReason) {
let handles = {
let Ok(mut state) = self.state.lock() else {
return;
};
if state.reason.is_some() {
return;
}
state.reason = Some(reason);
std::mem::take(&mut state.runs)
};
for handle in handles {
handle.cancel(reason.into_client());
}
}
pub fn reason(&self) -> Option<GatewayCancellationReason> {
self.state.lock().ok().and_then(|state| state.reason)
}
pub(crate) fn register(&self, handle: SippCancellationHandle) {
let reason = {
let Ok(mut state) = self.state.lock() else {
return;
};
match state.reason {
Some(reason) => Some(reason),
None => {
state.runs.push(handle.clone());
None
}
}
};
if let Some(reason) = reason {
handle.cancel(reason.into_client());
}
}
}
#[derive(Clone, Default)]
pub struct GatewayRequestContext {
pub request_id: Option<String>,
pub metadata: BTreeMap<String, serde_json::Value>,
pub cancellation: GatewayCancellation,
}
impl GatewayRequestContext {
pub fn new(request_id: Option<String>) -> Self {
Self {
request_id,
..Self::default()
}
}
pub fn with_metadata(mut self, metadata: BTreeMap<String, serde_json::Value>) -> Self {
self.metadata = metadata;
self
}
pub(crate) fn client_context(&self) -> SippRequestContext {
SippRequestContext {
request_id: self.request_id.clone(),
}
}
}