freeswitch_types/commands/endpoint/
user.rs1use super::{after_prefix, check_field, undeliverable, EndpointFieldFault};
2use crate::commands::originate::OriginateError;
3use crate::commands::variables::Variables;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "serde", serde(try_from = "config::UserEndpoint"))]
9#[non_exhaustive]
10pub struct UserEndpoint {
11 pub name: String,
13 #[cfg_attr(
15 feature = "serde",
16 serde(default, skip_serializing_if = "Option::is_none")
17 )]
18 pub domain: Option<String>,
19 #[cfg_attr(
21 feature = "serde",
22 serde(default, skip_serializing_if = "Option::is_none")
23 )]
24 pub variables: Option<Variables>,
25}
26
27impl UserEndpoint {
28 pub fn new(name: impl Into<String>) -> Self {
30 Self {
31 name: name.into(),
32 domain: None,
33 variables: None,
34 }
35 }
36
37 pub fn with_domain(mut self, domain: impl Into<String>) -> Self {
39 self.domain = Some(domain.into());
40 self
41 }
42}
43
44impl_dial_string_with_variables!(UserEndpoint, write_module_text, |this| match &this.domain {
45 Some(d) => format!("user/{}@{d}", this.name),
46 None => format!("user/{}", this.name),
47});
48
49impl UserEndpoint {
50 pub(crate) fn check_deliverable(&self) -> Result<(), OriginateError> {
53 check_field("user", "name", &self.name, &["@"])?;
54 if self
55 .name
56 .is_empty()
57 && self
58 .domain
59 .is_none()
60 {
61 return Err(undeliverable(
62 "user",
63 "name",
64 EndpointFieldFault::EmptyDialsNothing,
65 ));
66 }
67 match &self.domain {
68 Some(domain) => check_field("user", "domain", domain, &[]),
69 None => Ok(()),
70 }
71 }
72
73 pub(crate) fn parse_bare(text: &str) -> Result<Self, OriginateError> {
74 let rest = after_prefix(text, "user/", "user")?;
75 let ep = match rest.split_once('@') {
76 Some((name, domain)) => Self::new(name).with_domain(domain),
77 None => Self::new(rest),
78 };
79 ep.check_deliverable()?;
80 Ok(ep)
81 }
82}
83
84impl_endpoint_parse!(from_str: UserEndpoint);
85
86impl_endpoint_parse!(config:
87 UserEndpoint {
88 name: String,
89 ;
90 domain: Option<String>,
91 variables: Option<Variables>,
92 }
93);
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn user_endpoint_display() {
101 let ep = UserEndpoint {
102 name: "1000".into(),
103 domain: Some("example.com".into()),
104 variables: None,
105 };
106 assert_eq!(ep.to_string(), "user/1000@example.com");
107 }
108
109 #[test]
110 fn user_endpoint_display_no_domain() {
111 let ep = UserEndpoint {
112 name: "1000".into(),
113 domain: None,
114 variables: None,
115 };
116 assert_eq!(ep.to_string(), "user/1000");
117 }
118
119 #[test]
120 fn user_endpoint_from_str() {
121 let ep: UserEndpoint = "user/1000@example.com"
122 .parse()
123 .unwrap();
124 assert_eq!(ep.name, "1000");
125 assert_eq!(
126 ep.domain
127 .as_deref(),
128 Some("example.com")
129 );
130 }
131
132 #[test]
133 fn user_endpoint_from_str_no_domain() {
134 let ep: UserEndpoint = "user/1000"
135 .parse()
136 .unwrap();
137 assert_eq!(ep.name, "1000");
138 assert!(ep
139 .domain
140 .is_none());
141 }
142
143 #[test]
144 fn user_endpoint_round_trip() {
145 let ep = UserEndpoint {
146 name: "bob".into(),
147 domain: Some("example.com".into()),
148 variables: None,
149 };
150 let s = ep.to_string();
151 let parsed: UserEndpoint = s
152 .parse()
153 .unwrap();
154 assert_eq!(parsed, ep);
155 }
156
157 #[test]
158 fn serde_user_endpoint() {
159 let ep = UserEndpoint {
160 name: "1000".into(),
161 domain: Some("example.com".into()),
162 variables: None,
163 };
164 let json = serde_json::to_string(&ep).unwrap();
165 let parsed: UserEndpoint = serde_json::from_str(&json).unwrap();
166 assert_eq!(parsed, ep);
167 }
168
169 #[test]
170 fn serde_user_endpoint_no_domain() {
171 let ep = UserEndpoint {
172 name: "1000".into(),
173 domain: None,
174 variables: None,
175 };
176 let json = serde_json::to_string(&ep).unwrap();
177 let parsed: UserEndpoint = serde_json::from_str(&json).unwrap();
178 assert_eq!(parsed, ep);
179 }
180}