Skip to content

Commit

Permalink
ability to configure custom HttpClient (#62)
Browse files Browse the repository at this point in the history
* Usage of custom httpClient (#61)

* misc cleanup of comments/messages + fixed inconsistent linefeeds

* fix incomplete doc comment

Co-authored-by: thorstenfleischmann <[email protected]>
  • Loading branch information
eli-darkly and thorstenfleischmann authored Dec 2, 2020
1 parent 2bacb40 commit 85746be
Show file tree
Hide file tree
Showing 8 changed files with 597 additions and 447 deletions.
157 changes: 87 additions & 70 deletions src/LaunchDarkly.EventSource/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@
namespace LaunchDarkly.EventSource
{
/// <summary>
/// A class used
/// An immutable class containing configuration properties for <see cref="EventSource"/>.
/// </summary>
/// <seealso cref="ConfigurationBuilder"/>
public sealed class Configuration
{
{
#region Types

public delegate HttpContent HttpContentFactory();


public delegate HttpContent HttpContentFactory();

#endregion

#region Constants


public static readonly TimeSpan DefaultDelayRetryDuration = TimeSpan.FromMilliseconds(1000);
public static readonly TimeSpan DefaultConnectionTimeout = TimeSpan.FromMilliseconds(10000);
public static readonly TimeSpan DefaultReadTimeout = TimeSpan.FromMinutes(5);
Expand Down Expand Up @@ -50,8 +51,8 @@ public sealed class Configuration
/// </summary>
public TimeSpan DelayRetryDuration { get; }

/// <summary>
/// The amount of time a connection must stay open before the EventSource resets its backoff delay.
/// <summary>
/// The amount of time a connection must stay open before the EventSource resets its backoff delay.
/// </summary>
public TimeSpan BackoffResetThreshold { get; }

Expand Down Expand Up @@ -81,17 +82,22 @@ public sealed class Configuration
/// <summary>
/// The HttpMessageHandler that will be used for the HTTP client, or null for the default handler.
/// </summary>
public HttpMessageHandler MessageHandler { get; }

/// <summary>
/// The HTTP method that will be used when connecting to the EventSource API.
public HttpMessageHandler MessageHandler { get; }

/// <summary>
/// The HttpClient that will be used as the HTTP client, or null for a new HttpClient.
/// </summary>
public HttpClient HttpClient { get; }

/// <summary>
/// The HTTP method that will be used when connecting to the EventSource API.
/// </summary>
public HttpMethod Method { get; }

/// <summary>
/// A factory for HTTP request body content, if the HTTP method is one that allows a request body.
/// is one that allows a request body. This is in the form of a factory function because the request
/// may need to be sent more than once.
/// <summary>
/// A factory for HTTP request body content, if the HTTP method is one that allows a request body.
/// is one that allows a request body. This is in the form of a factory function because the request
/// may need to be sent more than once.
/// </summary>
public HttpContentFactory RequestBodyFactory { get; }

Expand Down Expand Up @@ -120,7 +126,8 @@ public TimeSpan MaximumDelayRetryDuration
/// </summary>
/// <param name="uri">The URI used to connect to the remote EventSource API.</param>
/// <param name="messageHandler">The message handler to use when sending API requests. If null, the <see cref="HttpClientHandler"/> is used.</param>
/// <param name="connectionTimeOut">The connection timeout. If null, defaults to 10 seconds.</param>
/// <param name="httpClient">The http client to be used when sending API requests. You can specify either <paramref name="messageHandler"/> or httpClient.</param>
/// <param name="connectionTimeout">The connection timeout. If null, defaults to 10 seconds. Can not be used with <paramref name="httpClient"/></param>
/// <param name="delayRetryDuration">The time to wait before attempting to reconnect to the EventSource API. If null, defaults to 1 second.</param>
/// <param name="readTimeout">The timeout when reading data from the EventSource API. If null, defaults to 5 minutes.</param>
/// <param name="requestHeaders">Request headers used when connecting to the remote EventSource API.</param>
Expand All @@ -129,37 +136,47 @@ public TimeSpan MaximumDelayRetryDuration
/// <param name="method">The HTTP method used to connect to the remote EventSource API.</param>
/// <param name="requestBodyFactory">A function that produces an HTTP request body to send to the remote EventSource API.</param>
/// <exception cref="ArgumentNullException">Throws ArgumentNullException if the uri parameter is null.</exception>
/// <exception cref="ArgumentException">Throws ArgumentException if both httpClient and messageHandler is not null.</exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <p><paramref name="connectionTimeOut"/> is less than zero. </p>
/// <p><paramref name="connectionTimeout"/> is less than zero. </p>
/// <p>- or - </p>
/// <p><paramref name="delayRetryDuration"/> is greater than 30 seconds. </p>
/// <p>- or - </p>
/// <p><paramref name="readTimeout"/> is less than zero. </p>
/// </exception>
public Configuration(Uri uri, HttpMessageHandler messageHandler = null, TimeSpan? connectionTimeout = null, TimeSpan? delayRetryDuration = null,
TimeSpan? readTimeout = null, IDictionary<string, string> requestHeaders = null, string lastEventId = null, ILog logger = null,
HttpMethod method = null, HttpContentFactory requestBodyFactory = null, TimeSpan? backoffResetThreshold = null)
HttpMethod method = null, HttpContentFactory requestBodyFactory = null, TimeSpan? backoffResetThreshold = null, HttpClient httpClient = null)
{
if (uri == null)
if (uri == null)
{
throw new ArgumentNullException(nameof(uri));
throw new ArgumentNullException(nameof(uri));
}

if (connectionTimeout.HasValue)
if (connectionTimeout.HasValue)
{
CheckConnectionTimeout(connectionTimeout.Value);
CheckConnectionTimeout(connectionTimeout.Value);
}
if (delayRetryDuration.HasValue)
{
CheckDelayRetryDuration(delayRetryDuration.Value);
if (delayRetryDuration.HasValue)
{
CheckDelayRetryDuration(delayRetryDuration.Value);
}
if (readTimeout.HasValue)
{
CheckReadTimeout(readTimeout.Value);
if (readTimeout.HasValue)
{
CheckReadTimeout(readTimeout.Value);
}
if (httpClient != null && messageHandler != null)
{
throw new ArgumentException(Resources.Configuration_HttpClient_With_MessageHandler, nameof(messageHandler));
}
if (httpClient != null && connectionTimeout != null)
{
throw new ArgumentException(Resources.Configuration_HttpClient_With_ConnectionTimeout, nameof(connectionTimeout));
}

Uri = uri;
MessageHandler = messageHandler;
HttpClient = httpClient;
ConnectionTimeout = connectionTimeout ?? DefaultConnectionTimeout;
DelayRetryDuration = delayRetryDuration ?? DefaultDelayRetryDuration;
BackoffResetThreshold = backoffResetThreshold ?? DefaultBackoffResetThreshold;
Expand All @@ -169,54 +186,54 @@ public Configuration(Uri uri, HttpMessageHandler messageHandler = null, TimeSpan
Logger = logger;
Method = method;
RequestBodyFactory = requestBodyFactory;
}

}

#endregion


#region Public Methods

/// <summary>
/// Provides a new <see cref="ConfigurationBuilder"/> for constructing a configuration.
/// </summary>
/// <param name="uri">the EventSource URI</param>
/// <returns>a new builder instance</returns>
public static ConfigurationBuilder Builder(Uri uri)
{
return new ConfigurationBuilder(uri);
}


/// <summary>
/// Provides a new <see cref="ConfigurationBuilder"/> for constructing a configuration.
/// </summary>
/// <param name="uri">the EventSource URI</param>
/// <returns>a new builder instance</returns>
public static ConfigurationBuilder Builder(Uri uri)
{
return new ConfigurationBuilder(uri);
}

#endregion


#region Internal Methods

internal static void CheckConnectionTimeout(TimeSpan connectionTimeout)
{
if (connectionTimeout != Timeout.InfiniteTimeSpan && connectionTimeout < TimeSpan.Zero)

internal static void CheckConnectionTimeout(TimeSpan connectionTimeout)
{
if (connectionTimeout != Timeout.InfiniteTimeSpan && connectionTimeout < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(connectionTimeout), Resources.Configuration_Value_Greater_Than_Zero);
}
}

internal static void CheckDelayRetryDuration(TimeSpan delayRetryDuration)
{
if (delayRetryDuration > MaximumRetryDuration)
{
throw new ArgumentOutOfRangeException(nameof(connectionTimeout), Resources.Configuration_Value_Greater_Than_Zero);
}
}

internal static void CheckDelayRetryDuration(TimeSpan delayRetryDuration)
{
if (delayRetryDuration > MaximumRetryDuration)
throw new ArgumentOutOfRangeException(nameof(delayRetryDuration), string.Format(Resources.Configuration_RetryDuration_Exceeded, MaximumRetryDuration.Milliseconds));
}
if (delayRetryDuration < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(delayRetryDuration), string.Format(Resources.Configuration_RetryDuration_Exceeded, MaximumRetryDuration.Milliseconds));
}
if (delayRetryDuration < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(delayRetryDuration), Resources.Configuration_Value_Greater_Than_Zero);
}
}

internal static void CheckReadTimeout(TimeSpan readTimeout)
{
if (readTimeout < TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(delayRetryDuration), Resources.Configuration_Value_Greater_Than_Zero);
}
}

internal static void CheckReadTimeout(TimeSpan readTimeout)
{
if (readTimeout < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(readTimeout), Resources.Configuration_Value_Greater_Than_Zero);
}
}

throw new ArgumentOutOfRangeException(nameof(readTimeout), Resources.Configuration_Value_Greater_Than_Zero);
}
}

#endregion
}
}
Loading

0 comments on commit 85746be

Please sign in to comment.