From 4775983802c906ecfbab809bcef36fb41f1eda84 Mon Sep 17 00:00:00 2001 From: Fedor <116813641+FedorKiselev76@users.noreply.github.com> Date: Sat, 27 Dec 2025 12:10:03 +0000 Subject: [PATCH] feat: add lookup of client INVITE dialogs by Call-ID --- src/dialog/dialog_layer.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/dialog/dialog_layer.rs b/src/dialog/dialog_layer.rs index ce734a3..53bcc23 100644 --- a/src/dialog/dialog_layer.rs +++ b/src/dialog/dialog_layer.rs @@ -1,6 +1,7 @@ use super::authenticate::Credential; use super::dialog::DialogStateSender; use super::{dialog::Dialog, server_dialog::ServerInviteDialog, DialogId}; +use crate::dialog::client_dialog::ClientInviteDialog; use crate::dialog::dialog::{DialogInner, DialogStateReceiver}; use crate::transaction::key::TransactionRole; use crate::transaction::make_tag; @@ -238,6 +239,33 @@ impl DialogLayer { Err(_) => None, } } + /// Returns all client-side INVITE dialogs (UAC) that share the given Call-ID. + /// + /// In a forking scenario, multiple client dialogs can exist for the same + /// Call-ID (same local From-tag, different remote To-tags). This helper + /// scans the internal dialog registry and returns all `ClientInviteDialog` + /// instances whose `DialogId.call_id` equals the provided `call_id`. + /// + /// The returned vector may be empty if no matching client dialogs are found. + pub fn get_client_dialog_by_call_id(&self, call_id: &str) -> Vec { + let dialogs = match self.inner.dialogs.read() { + Ok(guard) => guard, + Err(_) => { + // If the lock is poisoned, we conservatively return an empty list. + return Vec::new(); + } + }; + + dialogs + .values() + .filter_map(|dlg| match dlg { + Dialog::ClientInvite(client_dlg) if client_dlg.id().call_id == call_id => { + Some(client_dlg.clone()) + } + _ => None, + }) + .collect() + } pub fn remove_dialog(&self, id: &DialogId) { info!(%id, "remove dialog");