Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 9a2684d

Browse files
prepare 6.3.0 release (#147)
1 parent 3aeaacc commit 9a2684d

File tree

52 files changed

+1280
-830
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1280
-830
lines changed

src/LaunchDarkly.ServerSdk/Components.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,31 @@ public static PersistentDataStoreBuilder PersistentDataStore(IPersistentDataStor
311311
public static PollingDataSourceBuilder PollingDataSource() =>
312312
new PollingDataSourceBuilder();
313313

314+
/// <summary>
315+
/// Returns a builder for configuring custom service URIs.
316+
/// </summary>
317+
/// <remarks>
318+
/// <para>
319+
/// Passing this to <see cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)" />,
320+
/// after setting any desired properties on the builder, applies this configuration to the SDK.
321+
/// </para>
322+
/// <para>
323+
/// Most applications will never need to use this method. The main use case is when connecting
324+
/// to a <a href="https://docs.launchdarkly.com/home/advanced/relay-proxy">LaunchDarkly
325+
/// Relay Proxy</a> instance. For more information, see <see cref="ServiceEndpointsBuilder"/>.
326+
/// </para>
327+
/// </remarks>
328+
/// <example>
329+
/// <code>
330+
/// var config = Configuration.Builder(mobileKey)
331+
/// .ServiceEndpoints(Components.ServiceEndpoints().RelayProxy("http://my-relay-hostname:80"))
332+
/// .Build();
333+
/// </code>
334+
/// </example>
335+
/// <returns>a configuration builder</returns>
336+
/// <seealso cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)" />
337+
public static ServiceEndpointsBuilder ServiceEndpoints() => new ServiceEndpointsBuilder();
338+
314339
/// <summary>
315340
/// Returns a configurable factory for using streaming mode to get feature flag data.
316341
/// </summary>

src/LaunchDarkly.ServerSdk/Configuration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ public class Configuration
7878
/// </summary>
7979
public string SdkKey { get; }
8080

81+
/// <summary>
82+
/// Defines the base service URIs used by SDK components.
83+
/// </summary>
84+
public ServiceEndpoints ServiceEndpoints { get; }
85+
8186
/// <summary>
8287
/// How long the client constructor will block awaiting a successful connection to
8388
/// LaunchDarkly.
@@ -160,6 +165,7 @@ internal Configuration(ConfigurationBuilder builder)
160165
LoggingConfigurationFactory = builder._loggingConfigurationFactory;
161166
Offline = builder._offline;
162167
SdkKey = builder._sdkKey;
168+
ServiceEndpoints = (builder._serviceEndpointsBuilder ?? Components.ServiceEndpoints()).Build();
163169
StartWaitTime = builder._startWaitTime;
164170
}
165171

src/LaunchDarkly.ServerSdk/ConfigurationBuilder.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public sealed class ConfigurationBuilder
3939
internal ILoggingConfigurationFactory _loggingConfigurationFactory = null;
4040
internal bool _offline = false;
4141
internal string _sdkKey;
42+
internal ServiceEndpointsBuilder _serviceEndpointsBuilder = null;
4243
internal TimeSpan _startWaitTime = DefaultStartWaitTime;
4344

4445
#endregion
@@ -61,6 +62,7 @@ internal ConfigurationBuilder(Configuration copyFrom)
6162
_loggingConfigurationFactory = copyFrom.LoggingConfigurationFactory;
6263
_offline = copyFrom.Offline;
6364
_sdkKey = copyFrom.SdkKey;
65+
_serviceEndpointsBuilder = new ServiceEndpointsBuilder(copyFrom.ServiceEndpoints);
6466
_startWaitTime = copyFrom.StartWaitTime;
6567
}
6668

@@ -292,6 +294,24 @@ public ConfigurationBuilder SdkKey(string sdkKey)
292294
return this;
293295
}
294296

297+
/// <summary>
298+
/// Sets the SDK's service URIs, using a configuration builder obtained from
299+
/// <see cref="Components.ServiceEndpoints"/>.
300+
/// </summary>
301+
/// <remarks>
302+
/// This overwrites any previous options set with <see cref="ServiceEndpoints(ServiceEndpointsBuilder)"/>.
303+
/// If you want to set multiple options, set them on the same <see cref="ServiceEndpointsBuilder"/>.
304+
/// </remarks>
305+
/// <param name="serviceEndpointsBuilder">the subconfiguration builder object</param>
306+
/// <returns>the main configuration builder</returns>
307+
/// <seealso cref="Components.ServiceEndpoints"/>
308+
/// <seealso cref="ServiceEndpointsBuilder"/>
309+
public ConfigurationBuilder ServiceEndpoints(ServiceEndpointsBuilder serviceEndpointsBuilder)
310+
{
311+
_serviceEndpointsBuilder = serviceEndpointsBuilder;
312+
return this;
313+
}
314+
295315
/// <summary>
296316
/// Sets how long the client constructor will block awaiting a successful connection to
297317
/// LaunchDarkly.

src/LaunchDarkly.ServerSdk/Integrations/EventProcessorBuilder.cs

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Collections.Immutable;
4+
using LaunchDarkly.Logging;
45
using LaunchDarkly.Sdk.Internal;
56
using LaunchDarkly.Sdk.Internal.Events;
67
using LaunchDarkly.Sdk.Server.Interfaces;
78
using LaunchDarkly.Sdk.Server.Internal;
89
using LaunchDarkly.Sdk.Server.Internal.Events;
910

11+
using static LaunchDarkly.Sdk.Internal.Events.DiagnosticConfigProperties;
12+
1013
namespace LaunchDarkly.Sdk.Server.Integrations
1114
{
1215
/// <summary>
@@ -58,10 +61,8 @@ public sealed class EventProcessorBuilder : IEventProcessorFactory, IDiagnosticD
5861
/// </summary>
5962
public static readonly TimeSpan MinimumDiagnosticRecordingInterval = TimeSpan.FromMinutes(1);
6063

61-
internal static readonly Uri DefaultBaseUri = new Uri("https://events.launchdarkly.com");
62-
6364
internal bool _allAttributesPrivate = false;
64-
internal Uri _baseUri = DefaultBaseUri;
65+
internal Uri _baseUri = null;
6566
internal int _capacity = DefaultCapacity;
6667
internal TimeSpan _diagnosticRecordingInterval = DefaultDiagnosticRecordingInterval;
6768
internal TimeSpan _flushInterval = DefaultFlushInterval;
@@ -88,10 +89,18 @@ public EventProcessorBuilder AllAttributesPrivate(bool allAttributesPrivate)
8889
}
8990

9091
/// <summary>
91-
/// Sets a custom base URI for the events service.
92+
/// Deprecated method for setting a custom base URI for the events service.
9293
/// </summary>
9394
/// <remarks>
95+
/// <para>
96+
/// The preferred way to set this option is now with
97+
/// <see cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)"/>. If you set
98+
/// this deprecated option, it overrides any value that was set with
99+
/// <see cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)"/>.
100+
/// </para>
101+
/// <para>
94102
/// You will only need to change this value in the following cases:
103+
/// </para>
95104
/// <list type="bullet">
96105
/// <item><description>
97106
/// You are using the <a href="https://docs.launchdarkly.com/home/relay-proxy">Relay Proxy</a>.
@@ -104,9 +113,11 @@ public EventProcessorBuilder AllAttributesPrivate(bool allAttributesPrivate)
104113
/// </remarks>
105114
/// <param name="baseUri">the base URI of the events service; null to use the default</param>
106115
/// <returns>the builder</returns>
116+
/// <seealso cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)"/>
117+
[Obsolete("Use ConfigurationBuilder.ServiceEndpoints instead")]
107118
public EventProcessorBuilder BaseUri(Uri baseUri)
108119
{
109-
_baseUri = baseUri ?? DefaultBaseUri;
120+
_baseUri = baseUri;
110121
return this;
111122
}
112123

@@ -278,19 +289,7 @@ public EventProcessorBuilder UserKeysFlushInterval(TimeSpan userKeysFlushInterva
278289
/// <inheritdoc/>
279290
public IEventProcessor CreateEventProcessor(LdClientContext context)
280291
{
281-
var eventsConfig = new EventsConfiguration
282-
{
283-
AllAttributesPrivate = _allAttributesPrivate,
284-
DiagnosticRecordingInterval = _diagnosticRecordingInterval,
285-
EventCapacity = _capacity,
286-
EventFlushInterval = _flushInterval,
287-
EventsUri = _baseUri.AddPath("bulk"),
288-
DiagnosticUri = _baseUri.AddPath("diagnostic"),
289-
InlineUsersInEvents = _inlineUsersInEvents,
290-
PrivateAttributeNames = _privateAttributes.ToImmutableHashSet(),
291-
UserKeysCapacity = _userKeysCapacity,
292-
UserKeysFlushInterval = _userKeysFlushInterval
293-
};
292+
var eventsConfig = MakeEventsConfiguration(context.Basic, true);
294293
var logger = context.Basic.Logger.SubLogger(LogNames.EventsSubLog);
295294
var eventSender = _eventSender ??
296295
new DefaultEventSender(
@@ -310,20 +309,35 @@ public IEventProcessor CreateEventProcessor(LdClientContext context)
310309
));
311310
}
312311

313-
/// <inheritdoc/>
314-
public LdValue DescribeConfiguration(BasicConfiguration basic)
312+
private EventsConfiguration MakeEventsConfiguration(BasicConfiguration basic, bool logConfigErrors)
315313
{
316-
return LdValue.BuildObject()
317-
.Add("allAttributesPrivate", _allAttributesPrivate)
318-
.Add("customEventsURI", !_baseUri.Equals(DefaultBaseUri))
319-
.Add("diagnosticRecordingIntervalMillis", _diagnosticRecordingInterval.TotalMilliseconds)
320-
.Add("eventsCapacity", _capacity)
321-
.Add("eventsFlushIntervalMillis", _flushInterval.TotalMilliseconds)
322-
.Add("inlineUsersInEvents", _inlineUsersInEvents)
323-
.Add("samplingInterval", 0) // no longer implemented
324-
.Add("userKeysCapacity", _userKeysCapacity)
314+
var configuredBaseUri = _baseUri ??
315+
StandardEndpoints.SelectBaseUri(basic.ServiceEndpoints, e => e.EventsBaseUri, "Events",
316+
logConfigErrors ? basic.Logger : Logs.None.Logger(""));
317+
return new EventsConfiguration
318+
{
319+
AllAttributesPrivate = _allAttributesPrivate,
320+
DiagnosticRecordingInterval = _diagnosticRecordingInterval,
321+
EventCapacity = _capacity,
322+
EventFlushInterval = _flushInterval,
323+
EventsUri = configuredBaseUri.AddPath("bulk"),
324+
DiagnosticUri = configuredBaseUri.AddPath("diagnostic"),
325+
InlineUsersInEvents = _inlineUsersInEvents,
326+
PrivateAttributeNames = _privateAttributes.ToImmutableHashSet(),
327+
UserKeysCapacity = _userKeysCapacity,
328+
UserKeysFlushInterval = _userKeysFlushInterval
329+
};
330+
}
331+
332+
/// <inheritdoc/>
333+
public LdValue DescribeConfiguration(BasicConfiguration basic) =>
334+
LdValue.BuildObject()
335+
.WithEventProperties(
336+
MakeEventsConfiguration(basic, false),
337+
StandardEndpoints.IsCustomUri(basic.ServiceEndpoints, _baseUri, e => e.EventsBaseUri)
338+
)
339+
.Add("userKeysCapacity", _userKeysCapacity) // these two properties are specific to the server-side SDK
325340
.Add("userKeysFlushIntervalMillis", _userKeysFlushInterval.TotalMilliseconds)
326341
.Build();
327-
}
328342
}
329343
}

src/LaunchDarkly.ServerSdk/Integrations/HttpConfigurationBuilder.cs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using LaunchDarkly.Sdk.Internal.Http;
77
using LaunchDarkly.Sdk.Server.Interfaces;
88

9+
using static LaunchDarkly.Sdk.Internal.Events.DiagnosticConfigProperties;
10+
911
namespace LaunchDarkly.Sdk.Server.Integrations
1012
{
1113
/// <summary>
@@ -123,8 +125,15 @@ public HttpConfigurationBuilder MessageHandler(HttpMessageHandler messageHandler
123125
/// Sets an HTTP proxy for making connections to LaunchDarkly.
124126
/// </summary>
125127
/// <remarks>
128+
/// <para>
126129
/// This is ignored if you have specified a custom message handler with <see cref="MessageHandler(HttpMessageHandler)"/>,
127130
/// since proxy behavior is implemented by the message handler.
131+
/// </para>
132+
/// <para>
133+
/// Note that this is not the same as the <see href="https://docs.launchdarkly.com/home/relay-proxy">LaunchDarkly
134+
/// Relay Proxy</see>, which would be set with
135+
/// <see cref="ServiceEndpointsBuilder.RelayProxy(Uri)"/>.
136+
/// </para>
128137
/// </remarks>
129138
/// <example>
130139
/// <code>
@@ -213,6 +222,16 @@ public HttpConfigurationBuilder Wrapper(string wrapperName, string wrapperVersio
213222

214223
/// <inheritdoc/>
215224
public HttpConfiguration CreateHttpConfiguration(BasicConfiguration basicConfiguration)
225+
{
226+
var httpProperties = MakeHttpProperties(basicConfiguration);
227+
return new HttpConfiguration(
228+
httpProperties,
229+
_messageHandler,
230+
_responseStartTimeout
231+
);
232+
}
233+
234+
private HttpProperties MakeHttpProperties(BasicConfiguration basicConfiguration)
216235
{
217236
var httpProperties = HttpProperties.Default
218237
.WithAuthorizationKey(basicConfiguration.SdkKey)
@@ -230,33 +249,13 @@ public HttpConfiguration CreateHttpConfiguration(BasicConfiguration basicConfigu
230249
httpProperties = httpProperties.WithHeader(kv.Key, kv.Value);
231250
}
232251

233-
return new HttpConfiguration(
234-
httpProperties,
235-
_messageHandler,
236-
_responseStartTimeout
237-
);
252+
return httpProperties;
238253
}
239254

240255
/// <inheritdoc/>
241256
public LdValue DescribeConfiguration(BasicConfiguration basic) =>
242257
LdValue.BuildObject()
243-
.Add("connectTimeoutMillis", _connectTimeout.TotalMilliseconds)
244-
.Add("socketTimeoutMillis", _readTimeout.TotalMilliseconds)
245-
.Add("usingProxy", DetectProxy())
246-
.Add("usingProxyAuthenticator", DetectProxyAuth())
258+
.WithHttpProperties(MakeHttpProperties(basic))
247259
.Build();
248-
249-
// DetectProxy and DetectProxyAuth do not cover every mechanism that could be used to configure
250-
// a proxy; for instance, there is HttpClient.DefaultProxy, which only exists in .NET Core 3.x and
251-
// .NET 5.x. But since we're only trying to gather diagnostic stats, this doesn't have to be perfect.
252-
private bool DetectProxy() =>
253-
_proxy != null ||
254-
!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("HTTP_PROXY")) ||
255-
!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("HTTPS_PROXY")) ||
256-
!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("ALL_PROXY"));
257-
258-
private bool DetectProxyAuth() =>
259-
_proxy is WebProxy wp &&
260-
(wp.Credentials != null || wp.UseDefaultCredentials);
261260
}
262261
}

src/LaunchDarkly.ServerSdk/Integrations/PollingDataSourceBuilder.cs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System;
22
using LaunchDarkly.Sdk.Server.Interfaces;
3+
using LaunchDarkly.Sdk.Server.Internal;
34
using LaunchDarkly.Sdk.Server.Internal.DataSources;
45

6+
using static LaunchDarkly.Sdk.Internal.Events.DiagnosticConfigProperties;
7+
58
namespace LaunchDarkly.Sdk.Server.Integrations
69
{
710
/// <summary>
@@ -33,21 +36,27 @@ namespace LaunchDarkly.Sdk.Server.Integrations
3336
/// </example>
3437
public sealed class PollingDataSourceBuilder : IDataSourceFactory, IDiagnosticDescription
3538
{
36-
internal static readonly Uri DefaultBaseUri = new Uri("https://sdk.launchdarkly.com");
37-
3839
/// <summary>
3940
/// The default value for <see cref="PollInterval(TimeSpan)"/>: 30 seconds.
4041
/// </summary>
4142
public static readonly TimeSpan DefaultPollInterval = TimeSpan.FromSeconds(30);
4243

43-
internal Uri _baseUri = DefaultBaseUri;
44+
internal Uri _baseUri = null;
4445
internal TimeSpan _pollInterval = DefaultPollInterval;
4546

4647
/// <summary>
47-
/// Sets a custom base URI for the polling service.
48+
/// Deprecated method for setting a custom base URI for the polling service.
4849
/// </summary>
4950
/// <remarks>
51+
/// <para>
52+
/// The preferred way to set this option is now with
53+
/// <see cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)"/>. If you set
54+
/// this deprecated option, it overrides any value that was set with
55+
/// <see cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)"/>.
56+
/// </para>
57+
/// <para>
5058
/// You will only need to change this value in the following cases:
59+
/// </para>
5160
/// <list type="bullet">
5261
/// <item><description>
5362
/// You are using the <a href="https://docs.launchdarkly.com/home/relay-proxy">Relay Proxy</a>.
@@ -60,9 +69,11 @@ public sealed class PollingDataSourceBuilder : IDataSourceFactory, IDiagnosticDe
6069
/// </remarks>
6170
/// <param name="baseUri">the base URI of the polling service; null to use the default</param>
6271
/// <returns>the builder</returns>
72+
/// <seealso cref="ConfigurationBuilder.ServiceEndpoints(ServiceEndpointsBuilder)"/>
73+
[Obsolete("Use ConfigurationBuilder.ServiceEndpoints instead")]
6374
public PollingDataSourceBuilder BaseUri(Uri baseUri)
6475
{
65-
_baseUri = baseUri ?? DefaultBaseUri;
76+
_baseUri = baseUri;
6677
return this;
6778
}
6879

@@ -93,8 +104,12 @@ internal PollingDataSourceBuilder PollIntervalNoMinimum(TimeSpan pollInterval)
93104
/// <inheritdoc/>
94105
public IDataSource CreateDataSource(LdClientContext context, IDataSourceUpdates dataSourceUpdates)
95106
{
107+
var configuredBaseUri = _baseUri ??
108+
StandardEndpoints.SelectBaseUri(context.Basic.ServiceEndpoints, e => e.PollingBaseUri, "Polling",
109+
context.Basic.Logger);
110+
96111
context.Basic.Logger.Warn("You should only disable the streaming API if instructed to do so by LaunchDarkly support");
97-
FeatureRequestor requestor = new FeatureRequestor(context, _baseUri ?? DefaultBaseUri);
112+
FeatureRequestor requestor = new FeatureRequestor(context, configuredBaseUri);
98113
return new PollingProcessor(
99114
context,
100115
requestor,
@@ -104,16 +119,13 @@ public IDataSource CreateDataSource(LdClientContext context, IDataSourceUpdates
104119
}
105120

106121
/// <inheritdoc/>
107-
public LdValue DescribeConfiguration(BasicConfiguration basic)
108-
{
109-
return LdValue.BuildObject()
110-
.Add("streamingDisabled", true)
111-
.Add("customBaseURI",
112-
!(_baseUri ?? DefaultBaseUri).Equals(DefaultBaseUri))
113-
.Add("customStreamURI", false)
114-
.Add("pollingIntervalMillis", _pollInterval.TotalMilliseconds)
115-
.Add("usingRelayDaemon", false)
122+
public LdValue DescribeConfiguration(BasicConfiguration basic) =>
123+
LdValue.BuildObject()
124+
.WithPollingProperties(
125+
StandardEndpoints.IsCustomUri(basic.ServiceEndpoints, _baseUri, e => e.StreamingBaseUri),
126+
_pollInterval
127+
)
128+
.Add("usingRelayDaemon", false) // this property is specific to the server-side SDK
116129
.Build();
117-
}
118130
}
119131
}

0 commit comments

Comments
 (0)