Skip to content

Commit a0c283b

Browse files
authored
DEV-266 - Return null for discovery mode or multiple hosts in connection string (#280)
* Refactor address resolution logic in connectivity settings * Fix test * Make DefaultAddress private
1 parent 2d700ad commit a0c283b

8 files changed

+61
-55
lines changed

src/EventStore.Client/EventStoreClientConnectivitySettings.cs

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,26 @@ namespace EventStore.Client {
66
/// A class used to describe how to connect to an instance of EventStoreDB.
77
/// </summary>
88
public class EventStoreClientConnectivitySettings {
9-
private const int DefaultPort = 2113;
10-
private bool _insecure;
11-
private Uri? _address;
12-
9+
private const int DefaultPort = 2113;
10+
private bool _insecure;
11+
private Uri? _address;
12+
1313
/// <summary>
1414
/// The <see cref="Uri"/> of the EventStoreDB. Use this when connecting to a single node.
1515
/// </summary>
16-
public Uri Address {
17-
get { return _address != null && IsSingleNode ? _address : DefaultAddress; }
18-
set { _address = value; }
16+
public Uri? Address {
17+
get => IsSingleNode ? _address : null;
18+
set => _address = value;
1919
}
2020

21-
private Uri DefaultAddress {
22-
get {
23-
return new UriBuilder {
24-
Scheme = _insecure ? Uri.UriSchemeHttp : Uri.UriSchemeHttps,
25-
Port = DefaultPort
26-
}.Uri;
27-
}
28-
}
29-
21+
internal Uri ResolvedAddressOrDefault => Address ?? DefaultAddress;
22+
23+
private Uri DefaultAddress =>
24+
new UriBuilder {
25+
Scheme = _insecure ? Uri.UriSchemeHttp : Uri.UriSchemeHttps,
26+
Port = DefaultPort
27+
}.Uri;
28+
3029
/// <summary>
3130
/// The maximum number of times to attempt <see cref="EndPoint"/> discovery.
3231
/// </summary>
@@ -38,8 +37,8 @@ private Uri DefaultAddress {
3837
public EndPoint[] GossipSeeds =>
3938
((object?)DnsGossipSeeds ?? IpGossipSeeds) switch {
4039
DnsEndPoint[] dns => Array.ConvertAll<DnsEndPoint, EndPoint>(dns, x => x),
41-
IPEndPoint[] ip => Array.ConvertAll<IPEndPoint, EndPoint>(ip, x => x),
42-
_ => Array.Empty<EndPoint>()
40+
IPEndPoint[] ip => Array.ConvertAll<IPEndPoint, EndPoint>(ip, x => x),
41+
_ => Array.Empty<EndPoint>()
4342
};
4443

4544
/// <summary>
@@ -87,37 +86,31 @@ private Uri DefaultAddress {
8786
/// True if pointing to a single EventStoreDB node.
8887
/// </summary>
8988
public bool IsSingleNode => GossipSeeds.Length == 0;
90-
89+
9190
/// <summary>
9291
/// True if communicating over an insecure channel; otherwise false.
9392
/// </summary>
9493
public bool Insecure {
95-
get {
96-
return IsSingleNode
97-
? string.Equals(Address.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)
98-
: _insecure;
99-
}
100-
set {
101-
_insecure = value;
102-
}
94+
get => IsSingleNode ? string.Equals(Address?.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) : _insecure;
95+
set => _insecure = value;
10396
}
10497

10598
/// <summary>
106-
/// True if certificates will be validated; otherwise false.
99+
/// True if certificates will be validated; otherwise false.
107100
/// </summary>
108101
public bool TlsVerifyCert { get; set; } = true;
109-
102+
110103
/// <summary>
111104
/// The default <see cref="EventStoreClientConnectivitySettings"/>.
112105
/// </summary>
113106
public static EventStoreClientConnectivitySettings Default => new EventStoreClientConnectivitySettings {
114107
MaxDiscoverAttempts = 10,
115-
GossipTimeout = TimeSpan.FromSeconds(5),
116-
DiscoveryInterval = TimeSpan.FromMilliseconds(100),
117-
NodePreference = NodePreference.Leader,
118-
KeepAliveInterval = TimeSpan.FromSeconds(10),
119-
KeepAliveTimeout = TimeSpan.FromSeconds(10),
120-
TlsVerifyCert = true,
108+
GossipTimeout = TimeSpan.FromSeconds(5),
109+
DiscoveryInterval = TimeSpan.FromMilliseconds(100),
110+
NodePreference = NodePreference.Leader,
111+
KeepAliveInterval = TimeSpan.FromSeconds(10),
112+
KeepAliveTimeout = TimeSpan.FromSeconds(10),
113+
TlsVerifyCert = true,
121114
};
122115
}
123116
}

src/EventStore.Client/EventStoreClientSettings.ConnectionString.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private static class ConnectionStringParser {
4040
private const string UriSchemeDiscover = "esdb+discover";
4141

4242
private static readonly string[] Schemes = {"esdb", UriSchemeDiscover};
43-
private static readonly int DefaultPort = EventStoreClientConnectivitySettings.Default.Address.Port;
43+
private static readonly int DefaultPort = EventStoreClientConnectivitySettings.Default.ResolvedAddressOrDefault.Port;
4444
private static readonly bool DefaultUseTls = true;
4545

4646
private static readonly Dictionary<string, Type> SettingsType =

src/EventStore.Client/HttpFallback.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal class HttpFallback : IDisposable {
1313
private readonly string _addressScheme;
1414

1515
internal HttpFallback (EventStoreClientSettings settings) {
16-
_addressScheme = settings.ConnectivitySettings.Address.Scheme;
16+
_addressScheme = settings.ConnectivitySettings.ResolvedAddressOrDefault.Scheme;
1717
_defaultCredentials = settings.DefaultCredentials;
1818

1919
var handler = new HttpClientHandler();

src/EventStore.Client/SingleNodeChannelSelector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public SingleNodeChannelSelector(
2020

2121
_channelCache = channelCache;
2222

23-
var uri = settings.ConnectivitySettings.Address;
23+
var uri = settings.ConnectivitySettings.ResolvedAddressOrDefault;
2424
_endPoint = new DnsEndPoint(host: uri.Host, port: uri.Port);
2525
}
2626

src/EventStore.Client/SingleNodeHttpHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public SingleNodeHttpHandler(EventStoreClientSettings settings) {
1414
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
1515
CancellationToken cancellationToken) {
1616
request.RequestUri = new UriBuilder(request.RequestUri!) {
17-
Scheme = _settings.ConnectivitySettings.Address.Scheme
17+
Scheme = _settings.ConnectivitySettings.ResolvedAddressOrDefault.Scheme
1818
}.Uri;
1919
return base.SendAsync(request, cancellationToken);
2020
}

test/EventStore.Client.Tests.Common/Fixtures/Base/EventStoreClientFixtureBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ protected EventStoreClientFixtureBase(
5555
TestServer = new EventStoreTestServerExternal();
5656
else
5757
TestServer = GlobalEnvironment.UseCluster
58-
? new EventStoreTestServerCluster(hostCertificatePath, Settings.ConnectivitySettings.Address, env)
59-
: new EventStoreTestServer(hostCertificatePath, Settings.ConnectivitySettings.Address, env);
58+
? new EventStoreTestServerCluster(hostCertificatePath, Settings.ConnectivitySettings.ResolvedAddressOrDefault, env)
59+
: new EventStoreTestServer(hostCertificatePath, Settings.ConnectivitySettings.ResolvedAddressOrDefault, env);
6060
}
6161

6262
public IEventStoreTestServer TestServer { get; }

test/EventStore.Client.Tests.Common/Fixtures/EventStoreTestNode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static EventStoreFixtureOptions DefaultOptions() {
5757
protected override ContainerBuilder Configure() {
5858
var env = Options.Environment.Select(pair => $"{pair.Key}={pair.Value}").ToArray();
5959

60-
var port = Options.ClientSettings.ConnectivitySettings.Address.Port;
60+
var port = Options.ClientSettings.ConnectivitySettings.ResolvedAddressOrDefault.Port;
6161
var certsPath = Path.Combine(Environment.CurrentDirectory, "certs");
6262

6363
var containerName = port == 2113

test/EventStore.Client.Tests/ConnectionStringTests.cs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public class ConnectionStringTests {
2727
};
2828

2929
settings.ConnectivitySettings.Address =
30-
new UriBuilder(EventStoreClientConnectivitySettings.Default.Address) {
31-
Scheme = settings.ConnectivitySettings.Address.Scheme
30+
new UriBuilder(EventStoreClientConnectivitySettings.Default.ResolvedAddressOrDefault) {
31+
Scheme = settings.ConnectivitySettings.ResolvedAddressOrDefault.Scheme
3232
}.Uri;
3333

3434
yield return new object?[] {
@@ -48,8 +48,8 @@ public class ConnectionStringTests {
4848
};
4949

5050
ipGossipSettings.ConnectivitySettings.Address =
51-
new UriBuilder(EventStoreClientConnectivitySettings.Default.Address) {
52-
Scheme = ipGossipSettings.ConnectivitySettings.Address.Scheme
51+
new UriBuilder(EventStoreClientConnectivitySettings.Default.ResolvedAddressOrDefault) {
52+
Scheme = ipGossipSettings.ConnectivitySettings.ResolvedAddressOrDefault.Scheme
5353
}.Uri;
5454

5555
ipGossipSettings.ConnectivitySettings.DnsGossipSeeds = null;
@@ -73,7 +73,7 @@ public class ConnectionStringTests {
7373
singleNodeSettings.ConnectivitySettings.DnsGossipSeeds = null;
7474
singleNodeSettings.ConnectivitySettings.IpGossipSeeds = null;
7575
singleNodeSettings.ConnectivitySettings.Address = new UriBuilder(fixture.Create<Uri>()) {
76-
Scheme = singleNodeSettings.ConnectivitySettings.Address.Scheme
76+
Scheme = singleNodeSettings.ConnectivitySettings.ResolvedAddressOrDefault.Scheme
7777
}.Uri;
7878

7979
yield return new object?[] {
@@ -115,7 +115,7 @@ public void tls_verify_cert(bool tlsVerifyCert) {
115115
var result = EventStoreClientSettings.Create(connectionString);
116116
using var handler = result.CreateHttpMessageHandler?.Invoke();
117117
#if NET
118-
var socketsHandler = Assert.IsType<SocketsHttpHandler>(handler);
118+
var socketsHandler = Assert.IsType<SocketsHttpHandler>(handler);
119119
if (!tlsVerifyCert) {
120120
Assert.NotNull(socketsHandler.SslOptions.RemoteCertificateValidationCallback);
121121
Assert.True(
@@ -241,8 +241,8 @@ public void with_default_settings() {
241241

242242
Assert.Null(settings.ConnectionName);
243243
Assert.Equal(
244-
EventStoreClientConnectivitySettings.Default.Address.Scheme,
245-
settings.ConnectivitySettings.Address.Scheme
244+
EventStoreClientConnectivitySettings.Default.ResolvedAddressOrDefault.Scheme,
245+
settings.ConnectivitySettings.ResolvedAddressOrDefault.Scheme
246246
);
247247

248248
Assert.Equal(
@@ -301,7 +301,7 @@ public void use_tls(string connectionString, bool expectedUseTls) {
301301
var result = EventStoreClientSettings.Create(connectionString);
302302
var expectedScheme = expectedUseTls ? "https" : "http";
303303
Assert.NotEqual(expectedUseTls, result.ConnectivitySettings.Insecure);
304-
Assert.Equal(expectedScheme, result.ConnectivitySettings.Address.Scheme);
304+
Assert.Equal(expectedScheme, result.ConnectivitySettings.ResolvedAddressOrDefault.Scheme);
305305
}
306306

307307
[Theory]
@@ -334,7 +334,20 @@ public void allow_tls_override_for_single_node(string connectionString, bool? in
334334

335335
var expectedScheme = expectedUseTls ? "https" : "http";
336336
Assert.Equal(expectedUseTls, !settings.Insecure);
337-
Assert.Equal(expectedScheme, result.ConnectivitySettings.Address.Scheme);
337+
Assert.Equal(expectedScheme, result.ConnectivitySettings.ResolvedAddressOrDefault.Scheme);
338+
}
339+
340+
[Theory]
341+
[InlineData("esdb://localhost:1234", "localhost", 1234)]
342+
[InlineData("esdb://localhost:1234,localhost:4567", null, null)]
343+
[InlineData("esdb+discover://localhost:1234", null, null)]
344+
[InlineData("esdb+discover://localhost:1234,localhost:4567", null, null)]
345+
public void connection_string_with_custom_ports(string connectionString, string? expectedHost, int? expectedPort) {
346+
var result = EventStoreClientSettings.Create(connectionString);
347+
var connectivitySettings = result.ConnectivitySettings;
348+
349+
Assert.Equal(expectedHost, connectivitySettings.Address?.Host);
350+
Assert.Equal(expectedPort, connectivitySettings.Address?.Port);
338351
}
339352

340353
static string GetConnectionString(
@@ -350,7 +363,7 @@ static string GetScheme(EventStoreClientSettings settings) =>
350363

351364
static string GetAuthority(EventStoreClientSettings settings) =>
352365
settings.ConnectivitySettings.IsSingleNode
353-
? $"{settings.ConnectivitySettings.Address.Host}:{settings.ConnectivitySettings.Address.Port}"
366+
? $"{settings.ConnectivitySettings.ResolvedAddressOrDefault.Host}:{settings.ConnectivitySettings.ResolvedAddressOrDefault.Port}"
354367
: string.Join(
355368
",",
356369
settings.ConnectivitySettings.GossipSeeds.Select(x => $"{x.GetHost()}:{x.GetPort()}")
@@ -447,7 +460,7 @@ public bool Equals(EventStoreClientConnectivitySettings? x, EventStoreClientConn
447460
if (x.GetType() != y.GetType())
448461
return false;
449462

450-
return (!x.IsSingleNode || x.Address.Equals(y.Address)) &&
463+
return (!x.IsSingleNode || x.ResolvedAddressOrDefault.Equals(y.Address)) &&
451464
x.MaxDiscoverAttempts == y.MaxDiscoverAttempts &&
452465
x.GossipSeeds.SequenceEqual(y.GossipSeeds) &&
453466
x.GossipTimeout.Equals(y.GossipTimeout) &&
@@ -461,7 +474,7 @@ public bool Equals(EventStoreClientConnectivitySettings? x, EventStoreClientConn
461474
public int GetHashCode(EventStoreClientConnectivitySettings obj) =>
462475
obj.GossipSeeds.Aggregate(
463476
HashCode.Hash
464-
.Combine(obj.Address.GetHashCode())
477+
.Combine(obj.ResolvedAddressOrDefault.GetHashCode())
465478
.Combine(obj.MaxDiscoverAttempts)
466479
.Combine(obj.GossipTimeout)
467480
.Combine(obj.DiscoveryInterval)

0 commit comments

Comments
 (0)