rustpbx 0.4.9

A SIP PBX implementation in Rust
Documentation
use rsipstack::dialog::DialogId;
use rsipstack::dialog::dialog::{Dialog, DialogState, DialogStateReceiver};
use rsipstack::dialog::dialog_layer::DialogLayer;
use std::sync::Arc;
use tracing::{debug, info, warn};

pub struct DialogStateReceiverGuard {
    pub(super) dialog_layer: Arc<DialogLayer>,
    pub(super) receiver: Option<DialogStateReceiver>,
    pub(super) dialog_id: Option<DialogId>,
}

impl DialogStateReceiverGuard {
    pub fn new(dialog_layer: Arc<DialogLayer>, receiver: DialogStateReceiver) -> Self {
        Self {
            dialog_layer,
            receiver: Some(receiver),
            dialog_id: None,
        }
    }
    pub async fn recv(&mut self) -> Option<DialogState> {
        let receiver = self.receiver.as_mut()?;
        let state = receiver.recv().await;
        if let Some(ref s) = state {
            self.dialog_id = Some(s.id().clone());
        }
        state
    }

    pub fn take_receiver(&mut self) -> Option<DialogStateReceiver> {
        self.receiver.take()
    }

    pub fn disarm(&mut self) {
        self.dialog_id = None;
    }

    pub fn set_dialog_id(&mut self, dialog_id: DialogId) {
        self.dialog_id = Some(dialog_id);
    }

    fn take_dialog(&mut self) -> Option<Dialog> {
        let id = self.dialog_id.take()?;

        if let Some(dialog) = self.dialog_layer.get_dialog(&id) {
            info!(%id, "dialog removed on  drop");
            self.dialog_layer.remove_dialog(&id);
            return Some(dialog);
        }
        None
    }

    pub async fn drop_async(&mut self) {
        if let Some(dialog) = self.take_dialog()
            && let Err(e) = dialog.hangup().await
        {
            warn!(id=%dialog.id(), "error hanging up dialog on drop: {}", e);
        }
    }
}

impl Drop for DialogStateReceiverGuard {
    fn drop(&mut self) {
        if let Some(dialog) = self.take_dialog() {
            crate::utils::spawn(async move {
                if let Err(e) = dialog.hangup().await {
                    warn!(id=%dialog.id(), "error hanging up dialog on drop: {}", e);
                }
            });
        }
    }
}

pub struct ServerDialogGuard {
    pub dialog_layer: Arc<DialogLayer>,
    pub id: DialogId,
}

impl ServerDialogGuard {
    pub fn new(dialog_layer: Arc<DialogLayer>, id: DialogId) -> Self {
        Self { dialog_layer, id }
    }
}

impl Drop for ServerDialogGuard {
    fn drop(&mut self) {
        let dlg = match self.dialog_layer.get_dialog(&self.id) {
            Some(dlg) => {
                debug!(%self.id, state = %dlg.state(), "server dialog removed on drop");
                self.dialog_layer.remove_dialog(&self.id);
                match dlg {
                    Dialog::ServerInvite(dlg) => dlg,
                    _ => return,
                }
            }
            _ => return,
        };
        let state = dlg.state();
        if state.is_terminated() {
            return;
        }

        crate::utils::spawn(async move {
            if state.can_cancel() {
                dlg.reject(None, None).ok();
            } else {
                dlg.bye().await.ok();
            }
        });
    }
}

pub struct ClientDialogGuard {
    pub dialog_layer: Arc<DialogLayer>,
    pub id: DialogId,
}

impl ClientDialogGuard {
    pub fn new(dialog_layer: Arc<DialogLayer>, id: DialogId) -> Self {
        Self { dialog_layer, id }
    }

    pub fn id(&self) -> &DialogId {
        &self.id
    }
}

impl Drop for ClientDialogGuard {
    fn drop(&mut self) {
        let dlg = match self.dialog_layer.get_dialog(&self.id) {
            Some(dlg) => {
                debug!(%self.id, state = %dlg.state(), "client dialog removed on drop");
                self.dialog_layer.remove_dialog(&self.id);
                dlg
            }
            None => return,
        };

        if dlg.state().is_terminated() {
            return;
        }

        crate::utils::spawn(async move {
            if let Err(e) = dlg.hangup().await {
                warn!(id=%dlg.id(), "error hanging up client dialog on drop: {}", e);
            }
        });
    }
}