launchdarkly_server_sdk/
feature_requester_builders.rs1use crate::feature_requester::{FeatureRequester, HttpFeatureRequester};
2use crate::{LAUNCHDARKLY_INSTANCE_ID_HEADER, LAUNCHDARKLY_TAGS_HEADER};
3use http::Uri;
4use launchdarkly_sdk_transport::HttpTransport;
5use std::collections::HashMap;
6use std::str::FromStr;
7use thiserror::Error;
8
9#[non_exhaustive]
11#[derive(Debug, Error)]
12pub enum BuildError {
13 #[error("feature requester factory failed to build: {0}")]
15 InvalidConfig(String),
16}
17
18pub trait FeatureRequesterFactory: Send {
23 fn build(&self, tags: Option<String>) -> Result<Box<dyn FeatureRequester>, BuildError>;
25}
26
27pub struct HttpFeatureRequesterBuilder<T: HttpTransport> {
28 url: String,
29 sdk_key: String,
30 instance_id: Option<String>,
31 transport: T,
32}
33
34impl<T: HttpTransport> HttpFeatureRequesterBuilder<T> {
35 pub fn new(url: &str, sdk_key: &str, transport: T) -> Self {
36 Self {
37 transport,
38 url: url.into(),
39 sdk_key: sdk_key.into(),
40 instance_id: None,
41 }
42 }
43
44 pub fn with_instance_id(mut self, instance_id: &str) -> Self {
48 self.instance_id = Some(instance_id.into());
49 self
50 }
51}
52
53impl<T: HttpTransport> FeatureRequesterFactory for HttpFeatureRequesterBuilder<T> {
54 fn build(&self, tags: Option<String>) -> Result<Box<dyn FeatureRequester>, BuildError> {
55 let url = format!("{}/sdk/latest-all", self.url);
56
57 let mut default_headers = HashMap::<&str, String>::new();
58
59 if let Some(tags) = tags {
60 default_headers.insert(LAUNCHDARKLY_TAGS_HEADER, tags);
61 }
62 if let Some(instance_id) = &self.instance_id {
63 default_headers.insert(LAUNCHDARKLY_INSTANCE_ID_HEADER, instance_id.clone());
64 }
65
66 let url = Uri::from_str(url.as_str())
67 .map_err(|_| BuildError::InvalidConfig("Invalid base url provided".into()))?;
68
69 Ok(Box::new(HttpFeatureRequester::new(
70 self.transport.clone(),
71 url,
72 self.sdk_key.clone(),
73 default_headers,
74 )))
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn factory_handles_url_parsing_failure() {
84 let transport =
85 launchdarkly_sdk_transport::HyperTransport::new().expect("Failed to create transport");
86 let builder = HttpFeatureRequesterBuilder::new(
87 "This is clearly not a valid URL",
88 "sdk-key",
89 transport,
90 );
91 let result = builder.build(None);
92
93 match result {
94 Err(BuildError::InvalidConfig(_)) => (),
95 _ => panic!("Build did not return the right type of error"),
96 };
97 }
98}