1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
use super::client::BuildError;
const DEFAULT_POLLING_BASE_URL: &str = "https://sdk.launchdarkly.com";
const DEFAULT_STREAM_BASE_URL: &str = "https://stream.launchdarkly.com";
const DEFAULT_EVENTS_BASE_URL: &str = "https://events.launchdarkly.com";
/// Specifies the base service URLs used by SDK components.
pub struct ServiceEndpoints {
polling_base_url: String,
streaming_base_url: String,
events_base_url: String,
}
impl ServiceEndpoints {
pub fn polling_base_url(&self) -> &str {
self.polling_base_url.as_ref()
}
pub fn streaming_base_url(&self) -> &str {
self.streaming_base_url.as_ref()
}
pub fn events_base_url(&self) -> &str {
self.events_base_url.as_ref()
}
}
/// Used for configuring the SDKs service URLs.
///
/// The default behavior, if you do not change any of these properties, is that the SDK will connect
/// to the standard endpoints in the LaunchDarkly production service. There are several use cases for
/// changing these properties:
///
/// - You are using the <a href="https://docs.launchdarkly.com/home/advanced/relay-proxy">LaunchDarkly
/// Relay Proxy</a>. In this case, use [ServiceEndpointsBuilder::relay_proxy] with the URL of the relay proxy instance.
///
/// - You are connecting to a private instance of LaunchDarkly, rather than the standard production
/// services. In this case, there will be custom base URIs for each service. You need to configure
/// each endpoint with [ServiceEndpointsBuilder::polling_base_url],
/// [ServiceEndpointsBuilder::streaming_base_url], and [ServiceEndpointsBuilder::events_base_url].
///
/// - You are connecting to a test fixture that simulates the service endpoints. In this case, you
/// may set the base URLs to whatever you want, although the SDK will still set the URL paths to
/// the expected paths for LaunchDarkly services.
///
/// # Examples
///
/// Configure for a Relay Proxy instance.
/// ```
/// # use launchdarkly_server_sdk::{ServiceEndpointsBuilder, ConfigBuilder};
/// # fn main() {
/// ConfigBuilder::new("sdk-key").service_endpoints(ServiceEndpointsBuilder::new()
/// .relay_proxy("http://my-relay-hostname:8080"));
/// # }
/// ```
///
/// Configure for a private LaunchDarkly instance.
/// ```
/// # use launchdarkly_server_sdk::{ServiceEndpointsBuilder, ConfigBuilder};
/// # fn main() {
/// ConfigBuilder::new("sdk-key").service_endpoints(ServiceEndpointsBuilder::new()
/// .polling_base_url("https://sdk.my-private-instance.com")
/// .streaming_base_url("https://stream.my-private-instance.com")
/// .events_base_url("https://events.my-private-instance.com"));
/// # }
/// ```
#[derive(Clone)]
pub struct ServiceEndpointsBuilder {
polling_base_url: Option<String>,
streaming_base_url: Option<String>,
events_base_url: Option<String>,
}
impl ServiceEndpointsBuilder {
/// Create a new instance of [ServiceEndpointsBuilder] with no URLs specified.
pub fn new() -> ServiceEndpointsBuilder {
ServiceEndpointsBuilder {
polling_base_url: None,
streaming_base_url: None,
events_base_url: None,
}
}
/// Sets a custom base URL for the polling service.
pub fn polling_base_url(&mut self, url: &str) -> &mut Self {
self.polling_base_url = Some(String::from(url));
self
}
/// Sets a custom base URL for the streaming service.
pub fn streaming_base_url(&mut self, url: &str) -> &mut Self {
self.streaming_base_url = Some(String::from(url));
self
}
/// Sets a custom base URI for the events service.
pub fn events_base_url(&mut self, url: &str) -> &mut Self {
self.events_base_url = Some(String::from(url));
self
}
/// Specifies a single base URL for a Relay Proxy instance.
pub fn relay_proxy(&mut self, url: &str) -> &mut Self {
self.polling_base_url = Some(String::from(url));
self.streaming_base_url = Some(String::from(url));
self.events_base_url = Some(String::from(url));
self
}
/// Called internally by the SDK to create a configuration instance. Applications do not need
/// to call this method.
///
/// # Errors
///
/// When using custom endpoints it is important that all of the URLs are set.
/// If some URLs are set, but others are not, then this will return an error.
/// If no URLs are set, then the default values will be used.
/// This prevents a combination of custom and default values from being used.
pub fn build(&self) -> Result<ServiceEndpoints, BuildError> {
match (
&self.polling_base_url,
&self.streaming_base_url,
&self.events_base_url,
) {
(Some(polling_base_url), Some(streaming_base_url), Some(events_base_url)) => {
Ok(ServiceEndpoints {
polling_base_url: polling_base_url.trim_end_matches('/').to_string(),
streaming_base_url: streaming_base_url.trim_end_matches('/').to_string(),
events_base_url: events_base_url.trim_end_matches('/').to_string(),
})
}
(None, None, None) => Ok(ServiceEndpoints {
polling_base_url: String::from(DEFAULT_POLLING_BASE_URL),
streaming_base_url: String::from(DEFAULT_STREAM_BASE_URL),
events_base_url: String::from(DEFAULT_EVENTS_BASE_URL),
}),
_ => Err(BuildError::InvalidConfig(
"If you specify any endpoints,\
then you must specify all endpoints."
.into(),
)),
}
}
}
impl Default for ServiceEndpointsBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_case::test_case;
#[test_case("localhost", "localhost"; "requires no trimming")]
#[test_case("http://localhost", "http://localhost"; "requires no trimming with scheme")]
#[test_case("localhost/", "localhost"; "trims trailing slash")]
#[test_case("http://localhost/", "http://localhost"; "trims trailing slash with scheme")]
#[test_case("localhost////////", "localhost"; "trims multiple trailing slashes")]
fn service_endpoints_trims_base_urls(url: &str, expected: &str) {
let endpoints = ServiceEndpointsBuilder::new()
.polling_base_url(url)
.streaming_base_url(url)
.events_base_url(url)
.build()
.expect("Provided URLs should parse successfully");
assert_eq!(expected, endpoints.events_base_url());
assert_eq!(expected, endpoints.streaming_base_url());
assert_eq!(expected, endpoints.polling_base_url());
}
#[test]
fn default_configuration() -> Result<(), BuildError> {
let endpoints = ServiceEndpointsBuilder::new().build()?;
assert_eq!(
"https://events.launchdarkly.com",
endpoints.events_base_url()
);
assert_eq!(
"https://stream.launchdarkly.com",
endpoints.streaming_base_url()
);
assert_eq!("https://sdk.launchdarkly.com", endpoints.polling_base_url());
Ok(())
}
#[test]
fn full_custom_configuration() -> Result<(), BuildError> {
let endpoints = ServiceEndpointsBuilder::new()
.polling_base_url("https://sdk.my-private-instance.com")
.streaming_base_url("https://stream.my-private-instance.com")
.events_base_url("https://events.my-private-instance.com")
.build()?;
assert_eq!(
"https://events.my-private-instance.com",
endpoints.events_base_url()
);
assert_eq!(
"https://stream.my-private-instance.com",
endpoints.streaming_base_url()
);
assert_eq!(
"https://sdk.my-private-instance.com",
endpoints.polling_base_url()
);
Ok(())
}
#[test]
fn partial_definition() {
assert!(ServiceEndpointsBuilder::new()
.polling_base_url("https://sdk.my-private-instance.com")
.build()
.is_err());
}
#[test]
fn configure_relay_proxy() -> Result<(), BuildError> {
let endpoints = ServiceEndpointsBuilder::new()
.relay_proxy("http://my-relay-hostname:8080")
.build()?;
assert_eq!("http://my-relay-hostname:8080", endpoints.events_base_url());
assert_eq!(
"http://my-relay-hostname:8080",
endpoints.streaming_base_url()
);
assert_eq!(
"http://my-relay-hostname:8080",
endpoints.polling_base_url()
);
Ok(())
}
}