1use crate::util;
2use gethostname::gethostname;
3use std::fmt;
4use std::process;
5
6const BUS_ADDR_NAMESPACE: &str = "opensrf";
7
8#[derive(Debug, Clone, PartialEq)]
9enum AddressPurpose {
10 Router,
11 Service,
12 Client,
13}
14
15#[derive(Debug, Clone)]
26pub struct BusAddress {
27 full: String,
29
30 purpose: AddressPurpose,
31 domain: String,
32 username: String,
33
34 remainder: Option<String>,
36}
37
38impl fmt::Display for BusAddress {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 write!(f, "Address={}", &self.full)
41 }
42}
43
44impl BusAddress {
45 pub fn parse_str(full: &str) -> Result<Self, String> {
59 let parts: Vec<&str> = full.split(':').collect();
60
61 if parts.len() < 4 {
63 return Err(format!("BusAddress bad format: {}", full));
64 }
65
66 let purpose = match parts[1] {
67 "router" => AddressPurpose::Router,
68 "service" => AddressPurpose::Service,
69 "client" => AddressPurpose::Client,
70 _ => return Err(format!("Invalid address purpose: {}", parts[1])),
71 };
72
73 let username = parts[2].to_string();
74 let domain = parts[3].to_string();
75 let remainder = match parts.len() > 4 {
76 true => Some(parts[4..].join(":")),
77 _ => None,
78 };
79
80 Ok(BusAddress {
81 full: full.to_string(),
82 purpose,
83 username,
84 domain,
85 remainder,
86 })
87 }
88
89 pub fn for_router(username: &str, domain: &str) -> Self {
100 let full = format!("{}:router:{}:{}", BUS_ADDR_NAMESPACE, username, domain);
101
102 BusAddress {
103 full,
104 purpose: AddressPurpose::Router,
105 domain: domain.to_string(),
106 username: username.to_string(),
107 remainder: None,
108 }
109 }
110
111 pub fn for_bare_service(service: &str) -> Self {
123 BusAddress::for_service("_", "_", service)
124 }
125
126 pub fn for_service(username: &str, domain: &str, service: &str) -> Self {
127 let full = format!(
128 "{}:service:{}:{}:{}",
129 BUS_ADDR_NAMESPACE, username, domain, service
130 );
131
132 BusAddress {
133 full,
134 purpose: AddressPurpose::Service,
135 domain: domain.to_string(),
136 username: username.to_string(),
137 remainder: Some(service.to_string()),
138 }
139 }
140
141 pub fn for_client(username: &str, domain: &str) -> Self {
151 let remainder = format!(
152 "{}:{}:{}",
153 &gethostname().into_string().unwrap(),
154 process::id(),
155 &util::random_number(6)
156 );
157
158 let full = format!(
159 "{}:client:{}:{}:{}",
160 BUS_ADDR_NAMESPACE, username, domain, remainder
161 );
162
163 BusAddress {
164 full,
165 purpose: AddressPurpose::Client,
166 domain: domain.to_string(),
167 username: username.to_string(),
168 remainder: Some(remainder),
169 }
170 }
171
172 pub fn as_str(&self) -> &str {
174 &self.full
175 }
176 pub fn domain(&self) -> &str {
177 &self.domain
178 }
179 pub fn username(&self) -> &str {
180 &self.username
181 }
182 pub fn remainder(&self) -> Option<&str> {
184 self.remainder.as_deref()
185 }
186
187 fn compile(&mut self) {
188 let purpose = if self.is_service() {
189 "service"
190 } else if self.is_router() {
191 "router"
192 } else {
193 "client"
194 };
195
196 self.full = format!(
197 "{}:{}:{}:{}",
198 BUS_ADDR_NAMESPACE,
199 purpose,
200 self.username(),
201 self.domain()
202 );
203
204 if let Some(r) = self.remainder.as_ref() {
205 self.full += ":";
206 self.full += r;
207 }
208 }
209
210 pub fn set_domain(&mut self, s: &str) {
211 self.domain = s.to_string();
212 self.compile();
213 }
214 pub fn set_username(&mut self, s: &str) {
215 self.username = s.to_string();
216 self.compile();
217 }
218
219 pub fn set_remainder(&mut self, s: &str) {
233 self.remainder = Some(s.to_string());
234 self.compile();
235 }
236
237 pub fn service(&self) -> Option<&str> {
238 if self.is_service() {
239 self.remainder.as_deref()
240 } else {
241 None
242 }
243 }
244 pub fn is_client(&self) -> bool {
245 self.purpose == AddressPurpose::Client
246 }
247 pub fn is_service(&self) -> bool {
248 self.purpose == AddressPurpose::Service
249 }
250 pub fn is_router(&self) -> bool {
251 self.purpose == AddressPurpose::Router
252 }
253}