1use hyper::Uri;
2
3#[derive(Debug, Clone)]
5pub struct HttpExtract<'a> {
6 pub service: &'a str,
7 pub method: &'a str,
8}
9
10impl<'a> HttpExtract<'a> {
11 pub fn is_mailbox(&self) -> bool {
12 self.service == "mailbox"
13 }
14}
15
16#[derive(Debug, Clone)]
18pub struct GrpcExtract<'a> {
19 pub package: &'a str,
20 pub service: &'a str,
21 pub method: &'a str,
22}
23
24impl<'a> GrpcExtract<'a> {
25 pub fn is_mailbox(&self) -> bool {
26 self.service == "mailbox"
27 }
28}
29
30pub trait UriExtract {
32 fn extract_http(&self) -> Result<HttpExtract, &str>;
34
35 fn extract_grpc(&self) -> Result<GrpcExtract, &str>;
37}
38
39impl UriExtract for Uri {
41 fn extract_http(&self) -> Result<HttpExtract, &str> {
42 let (service, method) = extract_service_method(self.path())?;
43 Ok(HttpExtract { service, method })
44 }
45
46 fn extract_grpc(&self) -> Result<GrpcExtract, &str> {
47 let (svc_full, method) = extract_service_method(self.path())?;
48
49 let (package, service) = svc_full
50 .split_once('.')
51 .filter(|(p, s)| !p.is_empty() && !s.is_empty())
52 .ok_or(self.path())?;
53
54 Ok(GrpcExtract {
55 package,
56 service,
57 method,
58 })
59 }
60}
61
62fn extract_service_method(path: &str) -> Result<(&str, &str), &str> {
63 Ok(path
64 .trim_start_matches('/')
65 .split_once('/')
66 .filter(|(s, m)| !s.is_empty() && !m.is_empty())
67 .ok_or(path)?)
68}
69
70pub trait HeaderExtract {
72 fn extract_target(&self) -> Option<u32>;
74}
75
76impl HeaderExtract for hyper::HeaderMap<hyper::header::HeaderValue> {
77 fn extract_target(&self) -> Option<u32> {
78 for (k, v) in self.iter() {
79 if k.eq("target_service_id") {
80 let id = String::from_utf8_lossy(v.as_bytes());
81 let id: Result<u32, _> = id.parse();
82 return id.ok();
83 }
84 }
85 None
86 }
87}