Skip to content

Commit

Permalink
Refactor JetStream method results to use NatsResult
Browse files Browse the repository at this point in the history
  • Loading branch information
mtmk committed Oct 13, 2024
1 parent a64fd08 commit 71ed9d9
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 16 deletions.
38 changes: 38 additions & 0 deletions src/NATS.Client.Core/NatsResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Runtime.CompilerServices;

namespace NATS.Client.Core;

public readonly struct NatsResult<T>
{
private readonly T? _value;
private readonly Exception? _error;

public NatsResult(T value)
{
_value = value;
_error = null;
}

public NatsResult(Exception error)
{
_value = default;
_error = error;
}

public T Value => _value ?? ThrowValueIsNotSetException();

public Exception Error => _error ?? ThrowErrorIsNotSetException();

public bool Success => _error == null;

public static implicit operator NatsResult<T>(T value) => new(value);

public static implicit operator NatsResult<T>(Exception error) => new(error);

private static T ThrowValueIsNotSetException() => throw CreateInvalidOperationException("Result value is not set");

private static Exception ThrowErrorIsNotSetException() => throw CreateInvalidOperationException("Result error is not set");

[MethodImpl(MethodImplOptions.NoInlining)]
private static Exception CreateInvalidOperationException(string message) => new InvalidOperationException(message);
}
29 changes: 13 additions & 16 deletions src/NATS.Client.JetStream/NatsJSContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,19 +287,16 @@ internal async ValueTask<NatsJSResponse<TResponse>> JSRequestAsync<TRequest, TRe
where TRequest : class
where TResponse : class
{
var (response, exception) = await TryJSRequestAsync<TRequest, TResponse>(subject, request, cancellationToken).ConfigureAwait(false);
if (exception != null)
var result = await TryJSRequestAsync<TRequest, TResponse>(subject, request, cancellationToken).ConfigureAwait(false);
if (!result.Success)
{
throw exception;
throw result.Error;
}

if (response != null)
return response.Value;

throw new Exception("State error: No response received");
return result.Value;
}

internal async ValueTask<(NatsJSResponse<TResponse>?, Exception?)> TryJSRequestAsync<TRequest, TResponse>(
internal async ValueTask<NatsResult<NatsJSResponse<TResponse>>> TryJSRequestAsync<TRequest, TResponse>(
string subject,
TRequest? request,
CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -330,44 +327,44 @@ internal async ValueTask<NatsJSResponse<TResponse>> JSRequestAsync<TRequest, TRe
// API deserialize to the final type from the document.
if (msg.Data == null)
{
return (default, new NatsJSException("No response data received"));
return new NatsJSException("No response data received");
}

var jsonDocument = msg.Data;

if (jsonDocument.RootElement.TryGetProperty("error", out var errorElement))
{
var error = errorElement.Deserialize(JetStream.NatsJSJsonSerializerContext.Default.ApiError) ?? throw new NatsJSException("Can't parse JetStream error JSON payload");
return (new NatsJSResponse<TResponse>(default, error), default);
return new NatsJSResponse<TResponse>(default, error);
}

var jsonTypeInfo = NatsJSJsonSerializerContext.DefaultContext.GetTypeInfo(typeof(TResponse));
if (jsonTypeInfo == null)
{
return (default, new NatsJSException($"Unknown response type {typeof(TResponse)}"));
return new NatsJSException($"Unknown response type {typeof(TResponse)}");
}

var response = (TResponse?)jsonDocument.RootElement.Deserialize(jsonTypeInfo);

if (msg.Error is { } messageError)
{
return (default, messageError);
return messageError;
}

return (new NatsJSResponse<TResponse>(response, default), default);
return new NatsJSResponse<TResponse>(response, default);
}

if (sub is NatsSubBase { EndReason: NatsSubEndReason.Exception, Exception: not null } sb)
{
return (default, sb.Exception);
return sb.Exception;
}

if (sub.EndReason != NatsSubEndReason.None)
{
return (default, new NatsJSApiNoResponseException(sub.EndReason));
return new NatsJSApiNoResponseException(sub.EndReason);
}

return (default, new NatsJSApiNoResponseException());
return new NatsJSApiNoResponseException();
}

private static void ConvertDomain(StreamSource streamSource)
Expand Down

0 comments on commit 71ed9d9

Please sign in to comment.