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