Skip to content

Commit d1962d4

Browse files
committed
Add AOT support to Elastic.Transport.
Promote ApiKey as default implementation (also documentated default as part of client bootstrapping instruction on serverless). Make it easier to bootstrap a transport/cloudnodepool using a cloud endpoint an authentication method. No need to externally construct a cloud id.
1 parent ba4258c commit d1962d4

File tree

10 files changed

+64
-38
lines changed

10 files changed

+64
-38
lines changed

Playground/Playground.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<TargetFramework>net8.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
8+
<PublishAot>true</PublishAot>
89
</PropertyGroup>
910

1011
<ItemGroup>

Playground/Program.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,27 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5+
using Elastic.Transport;
56
using Elastic.Transport.Products.Elasticsearch;
7+
using HttpMethod = Elastic.Transport.HttpMethod;
68

79
var registration = new ElasticsearchProductRegistration(typeof(Elastic.Clients.Elasticsearch.ElasticsearchClient));
810

11+
var apiKey = Environment.GetEnvironmentVariable("ELASTIC_API_KEY") ?? throw new Exception();
12+
var url = Environment.GetEnvironmentVariable("ELASTIC_URL") ?? throw new Exception();
13+
14+
var configuration = new TransportConfiguration(new Uri(url), new ApiKey(apiKey), ElasticsearchProductRegistration.Default)
15+
{
16+
DebugMode = true
17+
};
18+
var transport = new DistributedTransport(configuration);
19+
20+
var response = transport.Request<EsResponse>(HttpMethod.GET, "/does-not-exist");
21+
Console.WriteLine(response.DebugInformation);
22+
23+
var dynamicResponse = transport.Request<DynamicResponse>(HttpMethod.GET, "/");
24+
Console.WriteLine(dynamicResponse.Body.Get<string>("version.build_flavor"));
25+
926
Console.WriteLine(registration.DefaultContentType ?? "NOT SPECIFIED");
27+
28+
public class EsResponse : ElasticsearchResponse;

src/Elastic.Transport/Components/NodePool/CloudNodePool.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace Elastic.Transport;
1616
/// </summary>
1717
public sealed class CloudNodePool : SingleNodePool
1818
{
19+
private readonly record struct ParsedCloudId(string ClusterName, Uri Uri);
20+
1921
/// <summary>
2022
/// An <see cref="NodePool"/> implementation that can be seeded with a cloud id
2123
/// and will signal the right defaults for the client to use for Elastic Cloud to <see cref="ITransportConfiguration"/>.
@@ -39,8 +41,17 @@ public sealed class CloudNodePool : SingleNodePool
3941
public CloudNodePool(string cloudId, AuthorizationHeader credentials) : this(ParseCloudId(cloudId)) =>
4042
AuthenticationHeader = credentials;
4143

44+
/// <summary>
45+
/// An <see cref="NodePool"/> implementation that can be seeded with a cloud enpoint
46+
/// and will signal the right defaults for the client to use for Elastic Cloud to <see cref="ITransportConfiguration"/>.
47+
/// </summary>
48+
/// <param name="cloudEndpoint">Elastic Cloud endpoint</param>
49+
/// <param name="credentials">The credentials to use with cloud</param>
50+
public CloudNodePool(Uri cloudEndpoint, AuthorizationHeader credentials) : this(CreateCloudId(cloudEndpoint)) =>
51+
AuthenticationHeader = credentials;
52+
4253
private CloudNodePool(ParsedCloudId parsedCloudId) : base(parsedCloudId.Uri) =>
43-
ClusterName = parsedCloudId.Name;
54+
ClusterName = parsedCloudId.ClusterName;
4455

4556
//TODO implement debugger display for NodePool implementations and display it there and its ToString()
4657
// ReSharper disable once UnusedAutoPropertyAccessor.Local
@@ -49,16 +60,13 @@ private CloudNodePool(ParsedCloudId parsedCloudId) : base(parsedCloudId.Uri) =>
4960
/// <inheritdoc cref="AuthorizationHeader"/>
5061
public AuthorizationHeader AuthenticationHeader { get; }
5162

52-
private readonly struct ParsedCloudId
63+
private static ParsedCloudId CreateCloudId(Uri uri)
5364
{
54-
public ParsedCloudId(string clusterName, Uri uri)
55-
{
56-
Name = clusterName;
57-
Uri = uri;
58-
}
59-
60-
public string Name { get; }
61-
public Uri Uri { get; }
65+
var moniker = $"{uri.Host}${Guid.NewGuid():N}";
66+
var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(moniker));
67+
var cloudId = $"name:{base64}";
68+
return new ParsedCloudId(cloudId, uri);
69+
6270
}
6371

6472
private static ParsedCloudId ParseCloudId(string cloudId)

src/Elastic.Transport/Components/Serialization/LowLevelRequestResponseSerializer.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System.Collections.Generic;
66
using System.Text.Json;
77
using System.Text.Json.Serialization;
8+
using System.Text.Json.Serialization.Metadata;
9+
using Elastic.Transport.Products.Elasticsearch;
810

911
namespace Elastic.Transport;
1012

@@ -32,6 +34,10 @@ public LowLevelRequestResponseSerializer(IReadOnlyCollection<JsonConverter>? con
3234
new ErrorCauseConverter(),
3335
new ErrorConverter(),
3436
new DynamicDictionaryConverter()
35-
], converters, options => { options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; })) { }
37+
], converters, options =>
38+
{
39+
options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
40+
options.TypeInfoResolver = JsonTypeInfoResolver.Combine(new DefaultJsonTypeInfoResolver(), ErrorSerializerContext.Default);
41+
})) { }
3642

3743
}

src/Elastic.Transport/Configuration/Security/ApiKey.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Elastic.Transport;
77
/// <summary>
88
/// Credentials for Api Key Authentication
99
/// </summary>
10-
public sealed class ApiKey : AuthorizationHeader
10+
public class ApiKey : AuthorizationHeader
1111
{
1212
private readonly string _apiKey;
1313

src/Elastic.Transport/Configuration/Security/Base64ApiKey.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,12 @@ namespace Elastic.Transport;
1010
/// <summary>
1111
/// Credentials for Api Key Authentication
1212
/// </summary>
13-
public sealed class Base64ApiKey : AuthorizationHeader
13+
public class Base64ApiKey : ApiKey
1414
{
15-
private readonly string _base64String;
16-
1715
/// <inheritdoc cref="Base64ApiKey"/>
18-
public Base64ApiKey(string id, string apiKey) =>
19-
_base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{id}:{apiKey}"));
16+
public Base64ApiKey(string id, string apiKey) :
17+
base(Convert.ToBase64String(Encoding.UTF8.GetBytes($"{id}:{apiKey}"))) {}
2018

2119
/// <inheritdoc cref="Base64ApiKey"/>
22-
public Base64ApiKey(string base64EncodedApiKey) =>
23-
_base64String = base64EncodedApiKey;
24-
25-
/// <inheritdoc cref="AuthorizationHeader.AuthScheme"/>
26-
public override string AuthScheme { get; } = "ApiKey";
27-
28-
/// <inheritdoc cref="AuthorizationHeader.TryGetAuthorizationParameters(out string)"/>
29-
public override bool TryGetAuthorizationParameters(out string value)
30-
{
31-
value = _base64String;
32-
return true;
33-
}
20+
public Base64ApiKey(string base64EncodedApiKey) : base(base64EncodedApiKey) {}
3421
}

src/Elastic.Transport/Configuration/TransportConfiguration.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,31 @@ public record TransportConfiguration : ITransportConfiguration
5454
/// </summary>
5555
/// <param name="uri">The root of the Elastic stack product node we want to connect to. Defaults to http://localhost:9200</param>
5656
/// <param name="productRegistration"><inheritdoc cref="ProductRegistration" path="/summary"/></param>
57-
public TransportConfiguration(Uri uri = null, ProductRegistration productRegistration = null)
57+
public TransportConfiguration(Uri? uri = null, ProductRegistration? productRegistration = null)
5858
: this(new SingleNodePool(uri ?? new Uri("http://localhost:9200")), productRegistration: productRegistration) { }
5959

6060
/// <summary>
6161
/// Sets up the client to communicate to Elastic Cloud using <paramref name="cloudId"/>,
6262
/// <para><see cref="CloudNodePool"/> documentation for more information on how to obtain your Cloud Id</para>
6363
/// </summary>
64-
public TransportConfiguration(string cloudId, BasicAuthentication credentials, ProductRegistration productRegistration = null)
64+
public TransportConfiguration(string cloudId, BasicAuthentication credentials, ProductRegistration? productRegistration = null)
6565
: this(new CloudNodePool(cloudId, credentials), productRegistration: productRegistration) { }
6666

6767
/// <summary>
6868
/// Sets up the client to communicate to Elastic Cloud using <paramref name="cloudId"/>,
6969
/// <para><see cref="CloudNodePool"/> documentation for more information on how to obtain your Cloud Id</para>
7070
/// </summary>
71-
public TransportConfiguration(string cloudId, Base64ApiKey credentials, ProductRegistration productRegistration = null)
71+
public TransportConfiguration(string cloudId, ApiKey credentials, ProductRegistration? productRegistration = null)
7272
: this(new CloudNodePool(cloudId, credentials), productRegistration: productRegistration) { }
7373

74+
/// <summary> Sets up the client to communicate to Elastic Cloud.</summary>
75+
public TransportConfiguration(Uri cloudEndpoint, BasicAuthentication credentials, ProductRegistration? productRegistration = null)
76+
: this(new CloudNodePool(cloudEndpoint, credentials), productRegistration: productRegistration) { }
77+
78+
/// <summary> Sets up the client to communicate to Elastic Cloud. </summary>
79+
public TransportConfiguration(Uri cloudEndpoint, ApiKey credentials, ProductRegistration? productRegistration = null)
80+
: this(new CloudNodePool(cloudEndpoint, credentials), productRegistration: productRegistration) { }
81+
7482
/// <summary> <inheritdoc cref="TransportConfigurationDescriptor" path="/summary"/></summary>
7583
/// <param name="nodePool"><inheritdoc cref="NodePool" path="/summary"/></param>
7684
/// <param name="requestInvoker"><inheritdoc cref="IRequestInvoker" path="/summary"/></param>

src/Elastic.Transport/Configuration/TransportConfigurationDescriptor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public TransportConfigurationDescriptor(string cloudId, BasicAuthentication cred
5151
/// Sets up the client to communicate to Elastic Cloud using <paramref name="cloudId"/>,
5252
/// <para><see cref="CloudNodePool"/> documentation for more information on how to obtain your Cloud Id</para>
5353
/// </summary>
54-
public TransportConfigurationDescriptor(string cloudId, Base64ApiKey credentials, ProductRegistration? productRegistration = null)
54+
public TransportConfigurationDescriptor(string cloudId, ApiKey credentials, ProductRegistration? productRegistration = null)
5555
: this(new CloudNodePool(cloudId, credentials), productRegistration: productRegistration) { }
5656

5757
/// <summary>

src/Elastic.Transport/DistributedTransport.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,12 @@
1919

2020
namespace Elastic.Transport;
2121

22-
/// <inheritdoc cref="ITransport{TConfiguration}" />
2322
/// <summary>
2423
/// Transport coordinates the client requests over the node pool nodes and is in charge of falling over on
2524
/// different nodes
2625
/// </summary>
2726
/// <param name="configuration">The configuration to use for this transport</param>
28-
public sealed class DistributedTransport(ITransportConfiguration configuration) : DistributedTransport<ITransportConfiguration>(configuration)
29-
{
30-
}
27+
public sealed class DistributedTransport(ITransportConfiguration configuration) : DistributedTransport<ITransportConfiguration>(configuration);
3128

3229
/// <summary>
3330
/// Transport coordinates the client requests over the node pool nodes and is in charge of falling over on

src/Elastic.Transport/Products/Elasticsearch/ErrorSerializationContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5-
using System.Text.Json;
65
using System.Text.Json.Serialization;
76
using System.Text.Json.Serialization.Metadata;
87

@@ -13,4 +12,5 @@ namespace Elastic.Transport.Products.Elasticsearch;
1312
[JsonSerializable(typeof(ErrorCause))]
1413
[JsonSerializable(typeof(ElasticsearchServerError))]
1514
[JsonSerializable(typeof(ElasticsearchResponse))]
15+
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Default)]
1616
public partial class ErrorSerializerContext : JsonSerializerContext;

0 commit comments

Comments
 (0)