use arc_swap::ArcSwapOption;
use std::sync::Arc;
use crate::types::{DialogId, IncomingCallInfo, MediaSessionId, SessionId};
#[derive(Clone)]
pub struct SessionRegistry {
current_session: Arc<ArcSwapOption<SessionId>>,
current_dialog: Arc<ArcSwapOption<DialogId>>,
current_media: Arc<ArcSwapOption<MediaSessionId>>,
pending_incoming_call: Arc<ArcSwapOption<IncomingCallInfo>>,
pending_incoming_request: Arc<ArcSwapOption<rvoip_sip_core::Request>>,
}
impl SessionRegistry {
pub fn new() -> Self {
Self {
current_session: Arc::new(ArcSwapOption::empty()),
current_dialog: Arc::new(ArcSwapOption::empty()),
current_media: Arc::new(ArcSwapOption::empty()),
pending_incoming_call: Arc::new(ArcSwapOption::empty()),
pending_incoming_request: Arc::new(ArcSwapOption::empty()),
}
}
pub async fn map_dialog(&self, session_id: SessionId, dialog_id: DialogId) {
self.current_session.store(Some(Arc::new(session_id)));
self.current_dialog.store(Some(Arc::new(dialog_id)));
}
pub async fn map_media(&self, session_id: SessionId, media_id: MediaSessionId) {
self.current_session.store(Some(Arc::new(session_id)));
self.current_media.store(Some(Arc::new(media_id)));
}
pub async fn get_session_by_dialog(&self, dialog_id: &DialogId) -> Option<SessionId> {
if self.current_dialog.load().as_deref() == Some(dialog_id) {
self.current_session.load().as_deref().cloned()
} else {
None
}
}
pub async fn get_session_by_media(&self, media_id: &MediaSessionId) -> Option<SessionId> {
if self.current_media.load().as_deref() == Some(media_id) {
self.current_session.load().as_deref().cloned()
} else {
None
}
}
pub async fn get_dialog_by_session(&self, session_id: &SessionId) -> Option<DialogId> {
if self.current_session.load().as_deref() == Some(session_id) {
self.current_dialog.load().as_deref().cloned()
} else {
None
}
}
pub async fn get_media_by_session(&self, session_id: &SessionId) -> Option<MediaSessionId> {
if self.current_session.load().as_deref() == Some(session_id) {
self.current_media.load().as_deref().cloned()
} else {
None
}
}
pub async fn remove_session(&self, session_id: &SessionId) {
if self.current_session.load().as_deref() == Some(session_id) {
self.current_session.store(None);
self.current_dialog.store(None);
self.current_media.store(None);
}
}
pub async fn contains_session(&self, session_id: &SessionId) -> bool {
self.current_session.load().as_deref() == Some(session_id)
}
pub async fn session_count(&self) -> usize {
usize::from(self.current_session.load().is_some())
}
pub async fn clear(&self) {
self.current_session.store(None);
self.current_dialog.store(None);
self.current_media.store(None);
self.pending_incoming_call.store(None);
self.pending_incoming_request.store(None);
}
pub async fn store_pending_incoming_call(
&self,
_session_id: SessionId,
info: IncomingCallInfo,
) {
self.pending_incoming_call.store(Some(Arc::new(info)));
}
pub async fn take_pending_incoming_call(
&self,
_session_id: &SessionId,
) -> Option<IncomingCallInfo> {
self.pending_incoming_call
.swap(None)
.map(|arc| (*arc).clone())
}
pub async fn store_pending_incoming_request(&self, request: Arc<rvoip_sip_core::Request>) {
self.pending_incoming_request.store(Some(request));
}
pub async fn peek_pending_incoming_request(&self) -> Option<Arc<rvoip_sip_core::Request>> {
self.pending_incoming_request.load_full()
}
pub async fn take_pending_incoming_request(&self) -> Option<Arc<rvoip_sip_core::Request>> {
self.pending_incoming_request.swap(None)
}
}
impl Default for SessionRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_dialog_mapping() {
let registry = SessionRegistry::new();
let session_id = SessionId::new();
let dialog_id = DialogId::new();
registry
.map_dialog(session_id.clone(), dialog_id.clone())
.await;
assert_eq!(
registry.get_session_by_dialog(&dialog_id).await,
Some(session_id.clone())
);
assert_eq!(
registry.get_dialog_by_session(&session_id).await,
Some(dialog_id)
);
}
#[tokio::test]
async fn test_media_mapping() {
let registry = SessionRegistry::new();
let session_id = SessionId::new();
let media_id = MediaSessionId::new_v4();
registry
.map_media(session_id.clone(), media_id.clone())
.await;
assert_eq!(
registry.get_session_by_media(&media_id).await,
Some(session_id.clone())
);
assert_eq!(
registry.get_media_by_session(&session_id).await,
Some(media_id)
);
}
#[tokio::test]
async fn test_remove_session() {
let registry = SessionRegistry::new();
let session_id = SessionId::new();
let dialog_id = DialogId::new();
let media_id = MediaSessionId::new_v4();
registry
.map_dialog(session_id.clone(), dialog_id.clone())
.await;
registry
.map_media(session_id.clone(), media_id.clone())
.await;
assert!(registry.contains_session(&session_id).await);
registry.remove_session(&session_id).await;
assert!(!registry.contains_session(&session_id).await);
assert_eq!(registry.get_session_by_dialog(&dialog_id).await, None);
assert_eq!(registry.get_session_by_media(&media_id).await, None);
}
#[tokio::test]
async fn test_session_count() {
let registry = SessionRegistry::new();
assert_eq!(registry.session_count().await, 0);
let session1 = SessionId::new();
let session2 = SessionId::new();
registry.map_dialog(session1.clone(), DialogId::new()).await;
registry.map_dialog(session2.clone(), DialogId::new()).await;
assert_eq!(registry.session_count().await, 1);
}
#[tokio::test]
async fn test_clear() {
let registry = SessionRegistry::new();
let session_id = SessionId::new();
registry
.map_dialog(session_id.clone(), DialogId::new())
.await;
registry
.map_media(session_id.clone(), MediaSessionId::new_v4())
.await;
registry.clear().await;
assert_eq!(registry.session_count().await, 0);
assert!(!registry.contains_session(&session_id).await);
}
}