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