using Microsoft.Extensions.Logging;
namespace MxGateway.Client;
///
/// Configures the gRPC channel used by the .NET MXAccess Gateway client.
///
public sealed class MxGatewayClientOptions
{
///
/// Gets the gateway endpoint URI (required).
///
public required Uri Endpoint { get; init; }
///
/// Gets the API key for gateway authentication (required).
///
public required string ApiKey { get; init; }
///
/// Gets a value indicating whether to use TLS for the gateway connection.
///
public bool UseTls { get; init; }
///
/// Gets the path to a CA certificate file for custom certificate validation.
///
public string? CaCertificatePath { get; init; }
///
/// Gets the server name override for SNI during TLS handshake.
///
public string? ServerNameOverride { get; init; }
///
/// Gets the timeout for establishing connection to the gateway.
///
public TimeSpan ConnectTimeout { get; init; } = TimeSpan.FromSeconds(10);
///
/// Gets the timeout budget for a unary gRPC operation. This is both the gRPC
/// deadline stamped on each individual attempt and the overall budget for the
/// whole safe-unary operation: for retryable calls the initial attempt, every
/// retry, and the backoff delays between them all share this single budget.
/// It is therefore an upper bound on the total wall-clock time a safe-unary
/// call can take, not a fresh per-retry allowance.
///
public TimeSpan DefaultCallTimeout { get; init; } = TimeSpan.FromSeconds(30);
///
/// Gets the optional timeout for streaming gRPC calls.
///
public TimeSpan? StreamTimeout { get; init; }
///
/// Gets the maximum size, in bytes, of a single gRPC message the client will
/// send or receive. Applied to both the send and receive limits of the
/// underlying channel. Defaults to 16 MiB.
///
public int MaxGrpcMessageBytes { get; init; } = 16 * 1024 * 1024;
///
/// Gets the retry configuration for safe unary calls.
///
public MxGatewayClientRetryOptions Retry { get; init; } = new();
///
/// Gets the logger factory for diagnostic logging.
///
public ILoggerFactory? LoggerFactory { get; init; }
///
/// Validates the client options for consistency and correctness.
///
/// Endpoint is null.
/// Options are invalid or inconsistent.
/// Timeout values are not greater than zero.
public void Validate()
{
ArgumentNullException.ThrowIfNull(Endpoint);
if (!Endpoint.IsAbsoluteUri)
{
throw new ArgumentException(
"The gateway endpoint must be an absolute URI.",
nameof(Endpoint));
}
if (string.IsNullOrWhiteSpace(ApiKey))
{
throw new ArgumentException(
"The gateway API key must not be empty.",
nameof(ApiKey));
}
if (ConnectTimeout <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(
nameof(ConnectTimeout),
"The connect timeout must be greater than zero.");
}
if (DefaultCallTimeout <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(
nameof(DefaultCallTimeout),
"The default call timeout must be greater than zero.");
}
if (StreamTimeout is not null && StreamTimeout <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(
nameof(StreamTimeout),
"The stream timeout must be greater than zero when configured.");
}
if (MaxGrpcMessageBytes <= 0)
{
throw new ArgumentOutOfRangeException(
nameof(MaxGrpcMessageBytes),
"The maximum gRPC message size must be greater than zero.");
}
if (UseTls && Endpoint.Scheme != Uri.UriSchemeHttps)
{
throw new ArgumentException(
"UseTls requires an https gateway endpoint.",
nameof(Endpoint));
}
if (!UseTls && Endpoint.Scheme == Uri.UriSchemeHttps)
{
throw new ArgumentException(
"An https gateway endpoint requires UseTls.",
nameof(Endpoint));
}
Retry.Validate();
}
}