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