open_feature_flagd/resolver/common/
upstream.rs1use anyhow::{Context, Result};
2use std::str::FromStr;
3use tonic::transport::{Endpoint, Uri};
4use tracing::debug;
5
6pub struct UpstreamConfig {
7 endpoint: Endpoint,
8 authority: Uri,
9}
10
11impl UpstreamConfig {
12 pub fn new(target: String, is_in_process: bool) -> Result<Self> {
13 debug!("Creating upstream config for target: {}", target);
14
15 if target.starts_with("http://") {
16 debug!("Target is already an HTTP endpoint");
17 let uri = Uri::from_str(&target)?;
18 let endpoint = Endpoint::from_shared(target)?;
19 return Ok(Self {
20 endpoint,
21 authority: uri
22 .authority()
23 .map(|a| a.as_str())
24 .unwrap_or_default()
25 .parse()?,
26 });
27 }
28
29 let (endpoint_str, authority) = if target.starts_with("envoy://") {
30 let uri = Uri::from_str(&target).context("Failed to parse target URI")?;
31 let authority = uri.path().trim_start_matches('/');
32
33 if authority.is_empty() {
34 return Err(anyhow::anyhow!("Service name (authority) cannot be empty"));
35 }
36
37 let host = uri.host().unwrap_or("localhost");
38 let port = uri.port_u16().unwrap_or(9211); (format!("http://{}:{}", host, port), authority.to_string())
41 } else {
42 let parts: Vec<&str> = target.split(':').collect();
43 let host = parts.first().unwrap_or(&"localhost").to_string();
44 let port = parts
45 .get(1)
46 .and_then(|p| p.parse().ok())
47 .unwrap_or(if is_in_process { 8015 } else { 8013 });
48
49 debug!("Using standard resolution with {}:{}", host, port);
50 (format!("http://{}:{}", host, port), host)
51 };
52
53 let endpoint = Endpoint::from_shared(endpoint_str)?;
54 let authority_uri =
55 Uri::from_str(authority.as_str()).context("Failed to parse authority")?;
56
57 Ok(Self {
58 endpoint,
59 authority: authority_uri,
60 })
61 }
62
63 pub fn endpoint(&self) -> &Endpoint {
64 &self.endpoint
65 }
66
67 pub fn authority(&self) -> &Uri {
68 &self.authority
69 }
70}