freeswitch_log_parser/session/
parse.rs1use std::str::FromStr;
4
5use freeswitch_types::{BridgeDialString, DialString};
6
7use crate::fields::processing_parts;
8use crate::message::new_channel_name;
9
10pub(super) struct DialplanContext {
11 pub(super) from: String,
12 pub(super) to: String,
13 pub(super) context: String,
14}
15
16pub(super) fn parse_dialplan_context(detail: &str) -> Option<&str> {
22 let rest = detail.strip_prefix("parsing [")?;
23 let bracket_end = rest.find(']')?;
24 let inner = &rest[..bracket_end];
25 let arrow = inner.find("->")?;
26 Some(&inner[..arrow])
27}
28
29pub(super) fn parse_processing_line(msg: &str) -> Option<DialplanContext> {
30 let parts = processing_parts(msg)?;
31 Some(DialplanContext {
32 from: msg[parts.head].to_string(),
33 to: msg[parts.dest].to_string(),
34 context: msg[parts.context].to_string(),
35 })
36}
37
38pub(super) fn parse_new_channel(detail: &str) -> Option<String> {
39 new_channel_name(detail).map(str::to_string)
40}
41
42pub(super) enum StateChange<'a> {
44 Channel(&'a str),
45 Call(&'a str),
46}
47
48pub(super) fn parse_state_change(detail: &str) -> Option<StateChange<'_>> {
51 let arrow = detail.find(" -> ")?;
52 let to = detail[arrow + 4..].trim();
53 if detail.contains("Callstate Change") {
54 Some(StateChange::Call(to))
55 } else {
56 Some(StateChange::Channel(to))
57 }
58}
59
60pub(super) fn parse_hangup(detail: &str) -> Option<String> {
61 if !detail.contains("Hangup ") {
62 return None;
63 }
64 let start = detail.rfind('[')?;
65 let end = detail[start..].find(']')?;
66 Some(detail[start + 1..start + end].to_string())
67}
68
69pub(super) fn is_answered(detail: &str) -> bool {
70 detail.contains("has been answered")
71}
72
73pub fn parse_bridge_args(arguments: &str) -> Option<BridgeInfo> {
80 let dial = BridgeDialString::from_str(arguments).ok()?;
81 let first_ep = dial.groups().first()?.first()?;
82 let origination_uuid = first_ep
85 .variables()
86 .and_then(|v| v.get("origination_uuid"))
87 .or_else(|| dial.variables().and_then(|v| v.get("origination_uuid")))
88 .map(|s| s.to_string());
89 let mut bare = first_ep.clone();
90 bare.set_variables(None);
91 let target_channel = bare.to_string();
92 Some(BridgeInfo {
93 origination_uuid,
94 target_channel,
95 })
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
100#[non_exhaustive]
101pub struct BridgeInfo {
102 pub origination_uuid: Option<String>,
104 pub target_channel: String,
107}
108
109pub(super) fn parse_originate_success(msg: &str) -> Option<String> {
111 let marker = "Peer UUID: ";
112 let idx = msg.find(marker)?;
113 let uuid = msg[idx + marker.len()..].trim();
114 if uuid.is_empty() {
115 None
116 } else {
117 Some(uuid.to_string())
118 }
119}
120
121pub(super) fn parse_originate_channel(msg: &str) -> Option<&str> {
125 let start = msg.find(" [")? + 2;
126 let end = msg[start..].find(']')?;
127 let chan = &msg[start..start + end];
128 if chan.is_empty() {
129 None
130 } else {
131 Some(chan)
132 }
133}