99using CouchDB . Driver . DTOs ;
1010using CouchDB . Driver . Exceptions ;
1111using System . Net ;
12+ using System . Text . Json ;
1213using System . Threading ;
1314using CouchDB . Driver . Options ;
1415using CouchDB . Driver . Query ;
16+ using Flurl . Http . Configuration ;
1517
1618namespace CouchDB . Driver ;
1719
@@ -20,11 +22,13 @@ namespace CouchDB.Driver;
2022/// </summary>
2123public partial class CouchClient : ICouchClient
2224{
25+ private const string DefaultHttpClientName = "Default" ;
2326 public const string DefaultDatabaseSplitDiscriminator = "split_discriminator" ;
2427 private DateTimeOffset ? _cookieCreationDate ;
2528 private string ? _cookieToken ;
2629
27- private readonly IFlurlClient _flurlClient ;
30+ private readonly Func < IFlurlClient > _flurlClient ;
31+ private readonly IFlurlClientCache _flurlClientCache ;
2832 private readonly CouchOptions _options ;
2933 private readonly string [ ] _systemDatabases = [ "_users" , "_replicator" , "_global_changes" ] ;
3034 public Uri Endpoint { get ; }
@@ -45,55 +49,69 @@ public CouchClient(string endpoint, Action<CouchOptionsBuilder>? couchSettingsFu
4549 /// <param name="endpoint">URI to the CouchDB endpoint.</param>
4650 /// <param name="couchSettingsFunc">A function to configure options.</param>
4751 public CouchClient ( Uri endpoint , Action < CouchOptionsBuilder > ? couchSettingsFunc = null )
52+ : this ( BuildOptions ( couchSettingsFunc , endpoint ) )
4853 {
49- var optionsBuilder = new CouchOptionsBuilder ( ) ;
50- couchSettingsFunc ? . Invoke ( optionsBuilder ) ;
51- _options = optionsBuilder . Options ;
52- Endpoint = endpoint ;
53- _flurlClient = GetConfiguredClient ( ) ;
5454 }
5555
5656 /// <summary>
5757 /// Creates a new CouchDB client.
5858 /// </summary>
5959 /// <param name="couchSettingsFunc">A function to configure options.</param>
6060 public CouchClient ( Action < CouchOptionsBuilder > ? couchSettingsFunc = null )
61+ : this ( BuildOptions ( couchSettingsFunc ) )
6162 {
62- var optionsBuilder = new CouchOptionsBuilder ( ) ;
63- couchSettingsFunc ? . Invoke ( optionsBuilder ) ;
63+ }
6464
65- if ( optionsBuilder . Options . Endpoint == null )
65+ internal CouchClient ( CouchOptions options )
66+ {
67+ if ( options . Endpoint == null )
6668 {
6769 throw new InvalidOperationException ( "Database endpoint must be set." ) ;
6870 }
6971
70- _options = optionsBuilder . Options ;
72+ _options = options ;
7173 Endpoint = _options . Endpoint ;
72- _flurlClient = GetConfiguredClient ( ) ;
74+ _flurlClientCache = GetConfiguredClientCache ( ) ;
75+ _flurlClient = ( ) => _flurlClientCache . Get ( DefaultHttpClientName )
76+ . WithSettings ( s =>
77+ {
78+ _options . JsonSerializerOptions ??= new JsonSerializerOptions ( ) ;
79+ _options . JsonSerializerOptions . PropertyNamingPolicy ??= JsonNamingPolicy . CamelCase ;
80+
81+ // TODO: Check type resolver
82+ _options . JsonSerializerOptions . TypeInfoResolver =
83+ new CouchJsonTypeInfoResolver ( _options . DatabaseSplitDiscriminator ) ;
84+ s . JsonSerializer = new DefaultJsonSerializer ( _options . JsonSerializerOptions ) ;
85+
86+ // TODO: Check authorization
87+ // s.HttpClientFactory = new CertClientFactory(_options.ServerCertificateCustomValidationCallback);
88+ } ) ;
7389 }
7490
75- internal CouchClient ( CouchOptions options )
91+ private static CouchOptions BuildOptions ( Action < CouchOptionsBuilder > ? couchSettingsFunc , Uri ? endpoint = null )
7692 {
77- if ( options . Endpoint == null )
93+ var optionsBuilder = new CouchOptionsBuilder ( ) ;
94+ couchSettingsFunc ? . Invoke ( optionsBuilder ) ;
95+
96+ if ( endpoint != null )
97+ {
98+ optionsBuilder . Options . Endpoint = endpoint ;
99+ }
100+
101+ if ( optionsBuilder . Options . Endpoint == null )
78102 {
79103 throw new InvalidOperationException ( "Database endpoint must be set." ) ;
80104 }
81105
82- _options = options ;
83- Endpoint = _options . Endpoint ;
84- _flurlClient = GetConfiguredClient ( ) ;
106+ return optionsBuilder . Options ;
85107 }
86108
87- private IFlurlClient GetConfiguredClient ( ) =>
88- new FlurlClient ( Endpoint . AbsoluteUri ) . Configure ( s =>
89- {
90- s . TypeInfoResolver = new CouchJsonTypeInfoResolver ( _options . DatabaseSplitDiscriminator )
91- s. BeforeCallAsync = OnBeforeCallAsync ;
92- if ( _options . ServerCertificateCustomValidationCallback != null )
93- {
94- s . HttpClientFactory = new CertClientFactory ( _options . ServerCertificateCustomValidationCallback ) ;
95- }
96- } ) ;
109+ private FlurlClientCache GetConfiguredClientCache ( )
110+ {
111+ var cache = new FlurlClientCache ( ) ;
112+ cache . Add ( DefaultHttpClientName , _options . Endpoint ! . AbsolutePath ) ;
113+ return cache ;
114+ }
97115
98116 #region Operations
99117
@@ -212,7 +230,8 @@ public Task<ICouchDatabase<TSource>> CreateDatabaseAsync<TSource>(int? shards =
212230 bool ? partitioned = null , string ? discriminator = null ,
213231 CancellationToken cancellationToken = default ) where TSource : CouchDocument
214232 {
215- return CreateDatabaseAsync < TSource > ( TypeExtensions . GetDatabaseName < TSource > ( ) , shards , replicas , partitioned , discriminator ,
233+ return CreateDatabaseAsync < TSource > ( TypeExtensions . GetDatabaseName < TSource > ( ) , shards , replicas , partitioned ,
234+ discriminator ,
216235 cancellationToken ) ;
217236 }
218237
@@ -221,7 +240,8 @@ public Task<ICouchDatabase<TSource>> GetOrCreateDatabaseAsync<TSource>(int? shar
221240 bool ? partitioned = null , string ? discriminator = null ,
222241 CancellationToken cancellationToken = default ) where TSource : CouchDocument
223242 {
224- return GetOrCreateDatabaseAsync < TSource > ( TypeExtensions . GetDatabaseName < TSource > ( ) , shards , replicas , partitioned , discriminator ,
243+ return GetOrCreateDatabaseAsync < TSource > ( TypeExtensions . GetDatabaseName < TSource > ( ) , shards , replicas ,
244+ partitioned , discriminator ,
225245 cancellationToken ) ;
226246 }
227247
@@ -418,7 +438,7 @@ public async Task<bool> RemoveReplicationAsync(string source, string target, Cou
418438
419439 private IFlurlRequest NewRequest ( )
420440 {
421- return _flurlClient . Request ( Endpoint ) ;
441+ return _flurlClient ( ) . Request ( Endpoint ) ;
422442 }
423443
424444 private QueryContext NewQueryContext ( string database )
@@ -457,7 +477,7 @@ protected virtual async Task DisposeAsync(bool disposing)
457477 await LogoutAsync ( ) . ConfigureAwait ( false ) ;
458478 }
459479
460- _flurlClient . Dispose ( ) ;
480+ _flurlClientCache . Clear ( ) ;
461481 }
462482 }
463483
0 commit comments