Skip to main content

active_call/
sip_util.rs

1//! Small SIP helpers shared across modules.
2
3/// Ensure a SIP URI carries a `sip:`/`sips:` scheme, prepending `sip:` when
4/// missing.
5pub fn ensure_sip_scheme(uri: String) -> String {
6    if uri.starts_with("sip:") || uri.starts_with("sips:") {
7        uri
8    } else {
9        format!("sip:{}", uri)
10    }
11}
12
13/// Convert a map of header name/value pairs into SIP headers.
14pub fn sip_headers_from_map(
15    headers: &std::collections::HashMap<String, String>,
16) -> Vec<rsipstack::rsip::Header> {
17    headers
18        .iter()
19        .map(|(k, v)| rsipstack::rsip::Header::Other(k.clone(), v.clone()))
20        .collect()
21}
22
23/// Extract the hangup-headers map stored under `_hangup_headers` in extras,
24/// converted to SIP headers.
25pub fn hangup_headers_from_extras(
26    extras: &std::collections::HashMap<String, serde_json::Value>,
27) -> Option<Vec<rsipstack::rsip::Header>> {
28    let value = extras.get("_hangup_headers")?;
29    let map =
30        serde_json::from_value::<std::collections::HashMap<String, String>>(value.clone()).ok()?;
31    let headers = sip_headers_from_map(&map);
32    (!headers.is_empty()).then_some(headers)
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    #[test]
40    fn adds_scheme_when_missing() {
41        assert_eq!(
42            ensure_sip_scheme("bob@example.com".into()),
43            "sip:bob@example.com"
44        );
45        assert_eq!(
46            ensure_sip_scheme("sip:bob@example.com".into()),
47            "sip:bob@example.com"
48        );
49        assert_eq!(
50            ensure_sip_scheme("sips:bob@example.com".into()),
51            "sips:bob@example.com"
52        );
53    }
54
55    #[test]
56    fn converts_header_maps() {
57        let mut map = std::collections::HashMap::new();
58        map.insert("X-Job-Id".to_string(), "42".to_string());
59        let headers = sip_headers_from_map(&map);
60        assert_eq!(headers.len(), 1);
61        assert!(matches!(&headers[0], rsipstack::rsip::Header::Other(k, v)
62            if k == "X-Job-Id" && v == "42"));
63    }
64
65    #[test]
66    fn extracts_hangup_headers_from_extras() {
67        let mut extras = std::collections::HashMap::new();
68        assert!(hangup_headers_from_extras(&extras).is_none());
69
70        let mut map = std::collections::HashMap::new();
71        map.insert("X-Reason".to_string(), "done".to_string());
72        extras.insert(
73            "_hangup_headers".to_string(),
74            serde_json::to_value(&map).unwrap(),
75        );
76        assert!(hangup_headers_from_extras(&extras).is_some());
77    }
78}