open_feature_flagd/resolver/common/
upstream.rs

1use 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); // Use Envoy port directly
39
40            (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}