Skip to content

Commit 0ea0703

Browse files
authored
chore: Merge 3.x branch into mainline (#156)
1 parent 1b3b695 commit 0ea0703

28 files changed

+2163
-729
lines changed

.github/actions/build-docs/action.yml

Lines changed: 0 additions & 9 deletions
This file was deleted.

.github/actions/ci/action.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
name: CI Workflow
2-
description: 'Shared CI workflow.'
2+
description: "Shared CI workflow."
3+
4+
inputs:
5+
cargo-flags:
6+
description: "Flags to pass to cargo commands."
7+
required: false
8+
default: ""
9+
cargo-test-flags:
10+
description: "Flags to pass to cargo test commands."
11+
required: false
12+
default: ""
313

414
runs:
515
using: composite
@@ -10,8 +20,8 @@ runs:
1020

1121
- name: Run tests
1222
shell: bash
13-
run: cargo test -p launchdarkly-server-sdk
23+
run: cargo test ${{ inputs.cargo-flags }} ${{ inputs.cargo-test-flags }} -p launchdarkly-server-sdk
1424

1525
- name: Run clippy checks
1626
shell: bash
17-
run: cargo clippy -p launchdarkly-server-sdk -- -D warnings
27+
run: cargo clippy ${{ inputs.cargo-flags }} -p launchdarkly-server-sdk -- -D warnings

.github/actions/contract-tests/action.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
name: Contract test runner
2-
description: 'Reusable contract runner action'
2+
description: "Reusable contract runner action"
33
inputs:
4-
tls_feature:
5-
description: 'Which TLS feature do you want to enable?'
4+
cargo-flags:
5+
description: "Flags to pass to cargo commands."
66
required: true
77
token:
8-
description: 'GH Token used for retrieving SDK test harness.'
8+
description: "GH Token used for retrieving SDK test harness."
99
required: true
1010

1111
runs:
1212
using: composite
1313
steps:
1414
- name: Build contract tests
1515
shell: bash
16-
run: TLS_FEATURE="${{ inputs.tls_feature }}" make build-contract-tests
16+
run: CARGO_FLAGS="${{ inputs.cargo-flags }}" make build-contract-tests
1717

1818
- name: Start contract test service
1919
shell: bash
20-
run: make start-contract-test-service-bg
20+
run: CARGO_FLAGS="${{ inputs.cargo-flags }}" make start-contract-test-service-bg
2121

2222
- uses: launchdarkly/gh-actions/actions/contract-tests@contract-tests-v1.0.2
2323
with:

.github/workflows/ci.yml

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,34 @@ on:
1212
jobs:
1313
ci-build:
1414
runs-on: ubuntu-latest
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
features:
19+
- name: "default (aws-lc-rs for crypto)"
20+
21+
- name: "no-features"
22+
cargo-flags: "--no-default-features"
23+
cargo-test-flags: "--lib"
24+
skip_contract_tests: "true"
25+
26+
- name: "hyper"
27+
cargo-flags: "--no-default-features --features hyper"
28+
cargo-test-flags: "--lib"
29+
30+
- name: "hyper-rustls-native-roots"
31+
cargo-flags: "--no-default-features --features hyper-rustls-native-roots"
32+
33+
- name: "hyper-rustls-webpki-roots"
34+
cargo-flags: "--no-default-features --features hyper-rustls-webpki-roots"
35+
36+
- name: "native-tls"
37+
cargo-flags: "--no-default-features --features native-tls"
38+
39+
- name: "openssl crypto"
40+
cargo-flags: "--no-default-features --features hyper-rustls-native-roots,crypto-openssl"
41+
42+
name: CI (${{ matrix.features.name }})
1543

1644
steps:
1745
- uses: actions/checkout@v4
@@ -26,20 +54,33 @@ jobs:
2654
rustup component add rustfmt clippy
2755
2856
- uses: ./.github/actions/ci
57+
with:
58+
cargo-flags: ${{ matrix.features.cargo-flags }}
59+
cargo-test-flags: ${{ matrix.features.cargo-test-flags }}
2960

30-
- name: "Run contract tests with hyper_rustls"
31-
uses: ./.github/actions/contract-tests
61+
- uses: ./.github/actions/contract-tests
62+
if: ${{ matrix.features.skip_contract_tests != 'true' }}
3263
with:
33-
tls_feature: "rustls"
64+
cargo-flags: ${{ matrix.features.cargo-flags }}
3465
token: ${{ secrets.GITHUB_TOKEN }}
3566

36-
- name: "Run contract tests with hyper_tls"
37-
uses: ./.github/actions/contract-tests
67+
build-docs:
68+
runs-on: ubuntu-latest
69+
name: Build Documentation (all features)
70+
71+
steps:
72+
- uses: actions/checkout@v4
3873
with:
39-
tls_feature: "tls"
40-
token: ${{ secrets.GITHUB_TOKEN }}
74+
fetch-depth: 0
75+
76+
- name: Setup rust tooling
77+
run: rustup override set nightly
78+
79+
- name: Install cargo-docs-rs
80+
run: cargo install cargo-docs-rs
4181

42-
- uses: ./.github/actions/build-docs
82+
- name: Build documentation
83+
run: cargo docs-rs -p launchdarkly-server-sdk
4384

4485
musl-build:
4586
runs-on: ubuntu-latest

.github/workflows/manual-publish.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ jobs:
2727
rustup component add rustfmt clippy
2828
2929
- uses: ./.github/actions/ci
30-
- uses: ./.github/actions/build-docs
3130

3231
- uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0
3332
name: "Get crates.io token"

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
TEMP_TEST_OUTPUT=/tmp/contract-test-service.log
2-
TLS_FEATURE ?= rustls
2+
CARGO_FLAGS ?=
33

44
build-contract-tests:
5-
cargo build -p contract-tests --release --no-default-features --features "$(TLS_FEATURE)"
5+
cargo build -p contract-tests --release $(CARGO_FLAGS)
66

77
start-contract-test-service: build-contract-tests
88
@./target/release/contract-tests
99

1010
start-contract-test-service-bg:
1111
@echo "Test service output will be captured in $(TEMP_TEST_OUTPUT)"
12-
@make start-contract-test-service >$(TEMP_TEST_OUTPUT) 2>&1 &
12+
@$(MAKE) start-contract-test-service >$(TEMP_TEST_OUTPUT) 2>&1 &
1313

1414
run-contract-tests:
1515
@curl -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/main/downloader/run.sh \

contract-tests/Cargo.toml

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,44 @@ license = "Apache-2.0"
99
actix = "0.13.0"
1010
actix-web = "4.2.1"
1111
env_logger = "0.10.0"
12+
eventsource-client = { version = "0.17.0" }
13+
launchdarkly-sdk-transport = { version = "0.1.0" }
1214
log = "0.4.14"
1315
launchdarkly-server-sdk = { path = "../launchdarkly-server-sdk/", default-features = false, features = ["event-compression"]}
1416
serde = { version = "1.0.132", features = ["derive"] }
1517
serde_json = "1.0.73"
1618
futures = "0.3.12"
17-
hyper = { version = "0.14.19", features = ["client"] }
18-
hyper-rustls = { version = "0.24.1" , optional = true, features = ["http2"]}
19-
hyper-tls = { version = "0.5.0", optional = true }
19+
hyper-util = { version = "0.1", features = ["client-legacy", "http1", "http2", "tokio"] }
20+
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "ring"], optional = true }
21+
hyper-tls = { version = "0.6.0", optional = true }
2022
reqwest = { version = "0.12.4", features = ["default", "blocking", "json"] }
2123
async-mutex = "1.4.0"
2224

2325
[features]
24-
default = ["rustls"]
25-
rustls = ["hyper-rustls/http1", "hyper-rustls/http2", "launchdarkly-server-sdk/rustls"]
26-
tls = ["hyper-tls"]
26+
default = ["hyper", "crypto-aws-lc-rs"]
27+
28+
crypto-aws-lc-rs = ["launchdarkly-server-sdk/crypto-aws-lc-rs"]
29+
crypto-openssl = ["launchdarkly-server-sdk/crypto-openssl"]
30+
31+
hyper = [
32+
"launchdarkly-sdk-transport/hyper",
33+
"eventsource-client/hyper"
34+
]
35+
hyper-rustls-native-roots = [
36+
"hyper",
37+
"dep:hyper-rustls",
38+
"launchdarkly-sdk-transport/hyper-rustls-native-roots",
39+
"eventsource-client/hyper-rustls-native-roots"
40+
]
41+
hyper-rustls-webpki-roots = [
42+
"hyper",
43+
"dep:hyper-rustls",
44+
"launchdarkly-sdk-transport/hyper-rustls-webpki-roots",
45+
"eventsource-client/hyper-rustls-webpki-roots"
46+
]
47+
native-tls = [
48+
"hyper",
49+
"dep:hyper-tls",
50+
"launchdarkly-sdk-transport/native-tls",
51+
"eventsource-client/native-tls"
52+
]

contract-tests/src/client_entity.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ const DEFAULT_EVENTS_BASE_URL: &str = "https://events.launchdarkly.com";
1111

1212
use launchdarkly_server_sdk::{
1313
ApplicationInfo, BuildError, Client, ConfigBuilder, Detail, EventProcessorBuilder,
14-
FlagDetailConfig, FlagValue, NullEventProcessorBuilder, PollingDataSourceBuilder,
14+
FlagDetailConfig, FlagFilter, FlagValue, NullEventProcessorBuilder, PollingDataSourceBuilder,
1515
ServiceEndpointsBuilder, StreamingDataSourceBuilder,
1616
};
1717

18+
#[cfg(any(feature = "crypto-aws-lc-rs", feature = "crypto-openssl"))]
19+
use crate::command_params::SecureModeHashResponse;
1820
use crate::command_params::{
1921
ContextBuildParams, ContextConvertParams, ContextParam, ContextResponse,
20-
MigrationOperationResponse, MigrationVariationResponse, SecureModeHashResponse,
22+
MigrationOperationResponse, MigrationVariationResponse,
2123
};
2224
use crate::HttpsConnector;
2325
use crate::{
@@ -37,6 +39,21 @@ impl ClientEntity {
3739
create_instance_params: CreateInstanceParams,
3840
connector: HttpsConnector,
3941
) -> Result<Self, BuildError> {
42+
let proxy = create_instance_params
43+
.configuration
44+
.proxy
45+
.unwrap_or_default()
46+
.http_proxy
47+
.unwrap_or_default();
48+
let mut transport_builder = launchdarkly_sdk_transport::HyperTransport::builder();
49+
if !proxy.is_empty() {
50+
transport_builder = transport_builder.proxy_url(proxy.clone());
51+
}
52+
53+
// Create fresh transports for this client to avoid shared connection pool issues
54+
let transport = transport_builder
55+
.build_with_connector(connector.clone())
56+
.map_err(|e| BuildError::InvalidConfig(e.to_string()))?;
4057
let mut config_builder =
4158
ConfigBuilder::new(&create_instance_params.configuration.credential);
4259

@@ -79,7 +96,7 @@ impl ClientEntity {
7996
if let Some(delay) = streaming.initial_retry_delay_ms {
8097
streaming_builder.initial_reconnect_delay(Duration::from_millis(delay));
8198
}
82-
streaming_builder.https_connector(connector.clone());
99+
streaming_builder.transport(transport.clone());
83100

84101
config_builder = config_builder.data_source(&streaming_builder);
85102
} else if let Some(polling) = create_instance_params.configuration.polling {
@@ -91,15 +108,15 @@ impl ClientEntity {
91108
if let Some(delay) = polling.poll_interval_ms {
92109
polling_builder.poll_interval(Duration::from_millis(delay));
93110
}
94-
polling_builder.https_connector(connector.clone());
111+
polling_builder.transport(transport.clone());
95112

96113
config_builder = config_builder.data_source(&polling_builder);
97114
} else {
98115
// If we didn't specify streaming or polling, we fall back to basic streaming. The only
99-
// customization we provide is the https connector to support testing multiple
100-
// connectors.
116+
// customization we provide is the transport to support testing multiple
117+
// transport implementations.
101118
let mut streaming_builder = StreamingDataSourceBuilder::new();
102-
streaming_builder.https_connector(connector.clone());
119+
streaming_builder.transport(transport.clone());
103120
config_builder = config_builder.data_source(&streaming_builder);
104121
}
105122

@@ -113,6 +130,7 @@ impl ClientEntity {
113130
processor_builder.capacity(capacity);
114131
}
115132
processor_builder.all_attributes_private(events.all_attributes_private);
133+
processor_builder.compress_events(false);
116134
if let Some(e) = events.enable_gzip {
117135
processor_builder.compress_events(e);
118136
}
@@ -124,7 +142,7 @@ impl ClientEntity {
124142
if let Some(attributes) = events.global_private_attributes {
125143
processor_builder.private_attributes(attributes);
126144
}
127-
processor_builder.https_connector(connector.clone());
145+
processor_builder.transport(transport);
128146
processor_builder.omit_anonymous_contexts(events.omit_anonymous_contexts);
129147

130148
config_builder.event_processor(&processor_builder)
@@ -214,14 +232,17 @@ impl ClientEntity {
214232
ContextResponse::from(Self::context_convert(params)),
215233
)))
216234
}
235+
#[cfg(any(feature = "crypto-aws-lc-rs", feature = "crypto-openssl"))]
217236
"secureModeHash" => {
218237
let params = command
219238
.secure_mode_hash
220239
.ok_or("secureModeHash params should be set")?;
240+
let hash = self
241+
.client
242+
.secure_mode_hash(&params.context)
243+
.map_err(|e| e.to_string())?;
221244
Ok(Some(CommandResponse::SecureModeHash(
222-
SecureModeHashResponse {
223-
result: self.client.secure_mode_hash(&params.context),
224-
},
245+
SecureModeHashResponse { result: hash },
225246
)))
226247
}
227248
"migrationVariation" => {
@@ -551,7 +572,7 @@ impl ClientEntity {
551572
}
552573

553574
if params.client_side_only {
554-
config.client_side_only();
575+
config.flag_filter(FlagFilter::CLIENT);
555576
}
556577

557578
if params.details_only_for_tracked_flags {

contract-tests/src/command_params.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub enum CommandResponse {
1010
EvaluateFlag(EvaluateFlagResponse),
1111
EvaluateAll(EvaluateAllFlagsResponse),
1212
ContextBuildOrConvert(ContextResponse),
13+
#[cfg(any(feature = "crypto-aws-lc-rs", feature = "crypto-openssl"))]
1314
SecureModeHash(SecureModeHashResponse),
1415
MigrationVariation(MigrationVariationResponse),
1516
MigrationOperation(MigrationOperationResponse),
@@ -25,6 +26,7 @@ pub struct CommandParams {
2526
pub identify_event: Option<IdentifyEventParams>,
2627
pub context_build: Option<ContextBuildParams>,
2728
pub context_convert: Option<ContextConvertParams>,
29+
#[cfg(any(feature = "crypto-aws-lc-rs", feature = "crypto-openssl"))]
2830
pub secure_mode_hash: Option<SecureModeHashParams>,
2931
pub migration_variation: Option<MigrationVariationParams>,
3032
pub migration_operation: Option<MigrationOperationParams>,
@@ -126,12 +128,14 @@ pub struct ContextConvertParams {
126128
pub input: String,
127129
}
128130

131+
#[cfg(any(feature = "crypto-aws-lc-rs", feature = "crypto-openssl"))]
129132
#[derive(Deserialize, Debug)]
130133
#[serde(rename_all = "camelCase")]
131134
pub struct SecureModeHashParams {
132135
pub context: Context,
133136
}
134137

138+
#[cfg(any(feature = "crypto-aws-lc-rs", feature = "crypto-openssl"))]
135139
#[derive(Serialize, Debug, Clone)]
136140
#[serde(rename_all = "camelCase")]
137141
pub struct SecureModeHashResponse {

0 commit comments

Comments
 (0)