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(); } }