1#[derive(Debug)]
2pub struct QueueNameComponents<'a> {
3 pub campaign: Option<&'a str>,
4 pub tenant: Option<&'a str>,
5 pub domain: &'a str,
6 pub routing_domain: Option<&'a str>,
7}
8
9fn crack_domain(domain: &str) -> (&str, Option<&str>) {
10 match domain.split_once('!') {
11 Some((domain, routing_domain)) => (domain, Some(routing_domain)),
12 None => (domain, None),
13 }
14}
15
16impl<'a> QueueNameComponents<'a> {
17 pub fn parse(name: &'a str) -> Self {
18 match name.split_once('@') {
19 Some((prefix, domain)) => match prefix.split_once(':') {
20 Some((campaign, tenant)) => {
21 let (domain, routing_domain) = crack_domain(domain);
22 Self {
23 campaign: Some(campaign),
24 tenant: Some(tenant),
25 domain,
26 routing_domain,
27 }
28 }
29 None => {
30 let (domain, routing_domain) = crack_domain(domain);
31 Self {
32 campaign: None,
33 tenant: Some(prefix),
34 domain,
35 routing_domain,
36 }
37 }
38 },
39 None => {
40 let (domain, routing_domain) = crack_domain(name);
41 Self {
42 campaign: None,
43 tenant: None,
44 domain,
45 routing_domain,
46 }
47 }
48 }
49 }
50
51 pub fn to_string(&self) -> String {
52 Self::format(self.campaign, self.tenant, self.domain, self.routing_domain)
53 }
54
55 pub fn format<C: AsRef<str>, T: AsRef<str>, D: AsRef<str>, RD: AsRef<str>>(
56 campaign: Option<C>,
57 tenant: Option<T>,
58 domain: D,
59 routing_domain: Option<RD>,
60 ) -> String {
61 let campaign: Option<&str> = campaign.as_ref().map(|c| c.as_ref());
62 let tenant: Option<&str> = tenant.as_ref().map(|c| c.as_ref());
63 let routing_domain: Option<String> =
64 routing_domain.as_ref().map(|c| format!("!{}", c.as_ref()));
65 let routing_domain = routing_domain.as_deref().unwrap_or("");
66 let domain: &str = domain.as_ref();
67 match (campaign, tenant) {
68 (Some(c), Some(t)) => format!("{c}:{t}@{domain}{routing_domain}"),
69 (Some(c), None) => format!("{c}:@{domain}{routing_domain}"),
70 (None, Some(t)) => format!("{t}@{domain}{routing_domain}"),
71 (None, None) => format!("{domain}{routing_domain}"),
72 }
73 }
74}
75
76#[cfg(test)]
77mod test {
78 use super::*;
79
80 #[test]
81 fn test_routing_domain_syntax() {
82 k9::assert_equal!(crack_domain("foo.com"), ("foo.com", None));
83 k9::assert_equal!(
84 crack_domain("foo.com!bar.com"),
85 ("foo.com", Some("bar.com"))
86 );
87 }
88
89 #[test]
90 fn test_routing_domain_with_port() {
91 k9::snapshot!(
92 QueueNameComponents::parse("foo.com:2025"),
93 r#"
94QueueNameComponents {
95 campaign: None,
96 tenant: None,
97 domain: "foo.com:2025",
98 routing_domain: None,
99}
100"#
101 );
102
103 k9::snapshot!(
104 QueueNameComponents::parse("foo.com!routing.com:2025"),
105 r#"
106QueueNameComponents {
107 campaign: None,
108 tenant: None,
109 domain: "foo.com",
110 routing_domain: Some(
111 "routing.com:2025",
112 ),
113}
114"#
115 );
116
117 k9::snapshot!(
118 QueueNameComponents::parse("tenant@foo.com!routing.com:2025"),
119 r#"
120QueueNameComponents {
121 campaign: None,
122 tenant: Some(
123 "tenant",
124 ),
125 domain: "foo.com",
126 routing_domain: Some(
127 "routing.com:2025",
128 ),
129}
130"#
131 );
132
133 k9::snapshot!(
134 QueueNameComponents::parse("campaign:@foo.com!routing.com:2025"),
135 r#"
136QueueNameComponents {
137 campaign: Some(
138 "campaign",
139 ),
140 tenant: Some(
141 "",
142 ),
143 domain: "foo.com",
144 routing_domain: Some(
145 "routing.com:2025",
146 ),
147}
148"#
149 );
150
151 k9::snapshot!(
152 QueueNameComponents::parse("campaign:tenant@foo.com!routing.com:2025"),
153 r#"
154QueueNameComponents {
155 campaign: Some(
156 "campaign",
157 ),
158 tenant: Some(
159 "tenant",
160 ),
161 domain: "foo.com",
162 routing_domain: Some(
163 "routing.com:2025",
164 ),
165}
166"#
167 );
168 }
169
170 #[test]
171 fn test_queue_name() {
172 k9::snapshot!(
173 QueueNameComponents::parse("foo.com"),
174 r#"
175QueueNameComponents {
176 campaign: None,
177 tenant: None,
178 domain: "foo.com",
179 routing_domain: None,
180}
181"#
182 );
183 k9::snapshot!(
184 QueueNameComponents::parse("tenant@foo.com"),
185 r#"
186QueueNameComponents {
187 campaign: None,
188 tenant: Some(
189 "tenant",
190 ),
191 domain: "foo.com",
192 routing_domain: None,
193}
194"#
195 );
196 k9::snapshot!(
197 QueueNameComponents::parse("campaign:@foo.com"),
198 r#"
199QueueNameComponents {
200 campaign: Some(
201 "campaign",
202 ),
203 tenant: Some(
204 "",
205 ),
206 domain: "foo.com",
207 routing_domain: None,
208}
209"#
210 );
211 k9::snapshot!(
212 QueueNameComponents::parse("campaign:tenant@foo.com"),
213 r#"
214QueueNameComponents {
215 campaign: Some(
216 "campaign",
217 ),
218 tenant: Some(
219 "tenant",
220 ),
221 domain: "foo.com",
222 routing_domain: None,
223}
224"#
225 );
226 k9::snapshot!(
227 QueueNameComponents::parse("campaign:tenant@foo.com!routing.com"),
228 r#"
229QueueNameComponents {
230 campaign: Some(
231 "campaign",
232 ),
233 tenant: Some(
234 "tenant",
235 ),
236 domain: "foo.com",
237 routing_domain: Some(
238 "routing.com",
239 ),
240}
241"#
242 );
243 }
244}