Skip to main content

launchdarkly_server_sdk/
lib.rs

1//! launchdarkly-server-sdk is the main crate for the LaunchDarkly SDK.
2//!
3//! This package contains the types and methods for the SDK client [Client] and its overall
4//! configuration.
5//!
6//! For more information and code examples, see the Rust SDK Reference:
7//! <https://docs.launchdarkly.com/sdk/server-side/rust>
8
9#![deny(rustdoc::missing_crate_level_docs)]
10#![deny(missing_docs)]
11
12#[macro_use]
13extern crate log;
14
15#[cfg(test)]
16#[macro_use]
17extern crate serde_json;
18
19use http::HeaderValue;
20pub use launchdarkly_server_sdk_evaluation::Error as EvalError;
21pub use launchdarkly_server_sdk_evaluation::{
22    AttributeValue, Context, ContextBuilder, Detail, FlagValue, Kind, MultiContextBuilder, Reason,
23    Reference,
24};
25use std::sync::LazyLock;
26
27pub use client::Client;
28
29// Re-export
30pub use client::{BuildError, StartError};
31pub use config::{ApplicationInfo, BuildError as ConfigBuildError, Config, ConfigBuilder};
32pub use data_source_builders::{
33    BuildError as DataSourceBuildError, PollingDataSourceBuilder, StreamingDataSourceBuilder,
34};
35pub use data_system_builders::{
36    BuildError as DataSystemBuildError, DataSystemBuilder, FDv2PollingBuilder, FDv2StreamingBuilder,
37};
38pub use evaluation::{FlagDetail, FlagDetailConfig, FlagFilter};
39pub use events::event::MigrationOpEvent;
40pub use events::processor::EventProcessor;
41pub use events::processor_builders::{
42    BuildError as EventProcessorBuildError, EventProcessorBuilder, NullEventProcessorBuilder,
43};
44pub use feature_requester_builders::{
45    BuildError as FeatureRequestBuilderError, FeatureRequesterFactory,
46};
47pub use launchdarkly_server_sdk_evaluation::{Flag, FlagBuilder, RuleBuilder, Segment, Versioned};
48pub use migrations::{
49    ExecutionOrder, MigrationOpTracker, Migrator, MigratorBuilder, Operation, Origin, Stage,
50};
51pub use service_endpoints::ServiceEndpointsBuilder;
52pub use stores::persistent_store::{PersistentDataStore, PersistentStoreError};
53pub use stores::persistent_store_builders::{
54    PersistentDataStoreBuilder, PersistentDataStoreFactory,
55};
56pub use stores::store_types::{AllData, DataKind, SerializedItem, StorageItem};
57pub use test_data::TestData;
58pub use version::version_string;
59
60mod client;
61mod config;
62mod data_source;
63mod data_source_builders;
64pub mod data_sources;
65mod data_system;
66mod data_system_builders;
67mod evaluation;
68mod events;
69mod fdv2;
70mod feature_requester;
71mod feature_requester_builders;
72mod migrations;
73mod reqwest;
74mod sampler;
75mod service_endpoints;
76mod stores;
77mod test_common;
78mod test_data;
79mod version;
80
81static LAUNCHDARKLY_EVENT_SCHEMA_HEADER: &str = "x-launchdarkly-event-schema";
82static LAUNCHDARKLY_PAYLOAD_ID_HEADER: &str = "x-launchdarkly-payload-id";
83static LAUNCHDARKLY_TAGS_HEADER: &str = "x-launchdarkly-tags";
84// X-LaunchDarkly-Instance-Id identifies this SDK instance for the purpose of estimating
85// server-connection-minutes when polling. It contains a v4 UUID that is generated once
86// per SDK instance and remains constant for the lifetime of the client.
87//
88// See: sdk-specs / SCMP-server-connection-minutes-polling.
89static LAUNCHDARKLY_INSTANCE_ID_HEADER: &str = "x-launchdarkly-instance-id";
90static CURRENT_EVENT_SCHEMA: &str = "4";
91
92static USER_AGENT: LazyLock<String> =
93    LazyLock::new(|| format!("RustServerClient/{}", version_string()));
94
95static EMPTY_HEADER: LazyLock<HeaderValue> = LazyLock::new(|| HeaderValue::from_static(""));
96
97#[cfg(all(test, feature = "float-roundtrip"))]
98mod tests {
99    use test_case::test_case;
100
101    // Fractional numbers must parse to the same f64 that Go's encoding/json produces, so that
102    // numeric flag values and numeric context attributes behave identically across LaunchDarkly
103    // SDKs. This requires serde_json's correctly-rounded parser, which the float-roundtrip
104    // feature selects.
105    #[test_case("130.65331632653061", 130.65331632653061)]
106    #[test_case("130.65331632653062", 130.65331632653061)]
107    #[test_case("130.65331632653063", 130.65331632653064)]
108    fn json_float_serialization_matches_go(float_as_string: &str, expected: f64) {
109        let parsed: f64 = serde_json::from_str(float_as_string).unwrap();
110        assert_eq!(expected, parsed);
111    }
112}