69 lines
3.3 KiB
C#
69 lines
3.3 KiB
C#
|
|
using Grpc.Core;
|
||
|
|
using Mishima.Nexus.Wire.V1;
|
||
|
|
using Robotico.Result.Errors;
|
||
|
|
|
||
|
|
namespace Robotico.Nexus.Client;
|
||
|
|
|
||
|
|
/// <summary>Maps <see cref="NexusStatus"/> wire envelopes and gRPC failures to <see cref="Robotico.Result.Result"/>.</summary>
|
||
|
|
internal static class NexusWireStatus
|
||
|
|
{
|
||
|
|
private const string OkCode = "OK";
|
||
|
|
|
||
|
|
/// <summary>Returns success when <paramref name="status"/> reports <c>OK</c>; otherwise a coded error.</summary>
|
||
|
|
internal static Robotico.Result.Result ToResult(NexusStatus? status)
|
||
|
|
{
|
||
|
|
if (status is null)
|
||
|
|
{
|
||
|
|
return Robotico.Result.Result.Error(NexusErrors.Error("Nexus response is missing a status envelope.", NexusErrors.WireFailed));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (string.Equals(status.Code, OkCode, StringComparison.Ordinal))
|
||
|
|
{
|
||
|
|
return Robotico.Result.Result.Success();
|
||
|
|
}
|
||
|
|
|
||
|
|
string code = string.IsNullOrWhiteSpace(status.Code) ? NexusErrors.WireFailed : status.Code;
|
||
|
|
string message = string.IsNullOrWhiteSpace(status.Message) ? "Nexus call failed." : status.Message;
|
||
|
|
return Robotico.Result.Result.Error(NexusErrors.Error(message, code));
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>Maps status to <see cref="Robotico.Result.Result{T}"/>, carrying <paramref name="value"/> on success.</summary>
|
||
|
|
internal static Robotico.Result.Result<T> ToResult<T>(NexusStatus? status, T value)
|
||
|
|
{
|
||
|
|
Robotico.Result.Result plain = ToResult(status);
|
||
|
|
return plain.IsError(out IError? error) ? Robotico.Result.Result.Error<T>(error!) : Robotico.Result.Result.Success(value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>True when <paramref name="status"/> reports <c>OK</c>.</summary>
|
||
|
|
internal static bool IsOk(NexusStatus? status) =>
|
||
|
|
status is not null && string.Equals(status.Code, OkCode, StringComparison.Ordinal);
|
||
|
|
|
||
|
|
/// <summary>Maps a failed gRPC call into a coded <see cref="IError"/>.</summary>
|
||
|
|
internal static IError FromException(RpcException exception)
|
||
|
|
{
|
||
|
|
string code = exception.StatusCode switch
|
||
|
|
{
|
||
|
|
StatusCode.OK => NexusErrors.WireFailed,
|
||
|
|
StatusCode.Cancelled => NexusErrors.Unavailable,
|
||
|
|
StatusCode.Unknown => NexusErrors.WireFailed,
|
||
|
|
StatusCode.InvalidArgument => NexusErrors.InvalidArgument,
|
||
|
|
StatusCode.DeadlineExceeded => NexusErrors.Unavailable,
|
||
|
|
StatusCode.NotFound => NexusErrors.NotFound,
|
||
|
|
StatusCode.AlreadyExists => NexusErrors.AlreadyExists,
|
||
|
|
StatusCode.PermissionDenied => NexusErrors.WireFailed,
|
||
|
|
StatusCode.ResourceExhausted => NexusErrors.Unavailable,
|
||
|
|
StatusCode.FailedPrecondition => NexusErrors.InvalidArgument,
|
||
|
|
StatusCode.Aborted => NexusErrors.WireFailed,
|
||
|
|
StatusCode.OutOfRange => NexusErrors.InvalidArgument,
|
||
|
|
StatusCode.Unimplemented => NexusErrors.WireFailed,
|
||
|
|
StatusCode.Internal => NexusErrors.WireFailed,
|
||
|
|
StatusCode.Unavailable => NexusErrors.Unavailable,
|
||
|
|
StatusCode.DataLoss => NexusErrors.WireFailed,
|
||
|
|
StatusCode.Unauthenticated => NexusErrors.WireFailed,
|
||
|
|
_ => NexusErrors.WireFailed,
|
||
|
|
};
|
||
|
|
string detail = string.IsNullOrWhiteSpace(exception.Status.Detail) ? exception.Message : exception.Status.Detail;
|
||
|
|
return NexusErrors.Error($"gRPC call failed ({exception.StatusCode}): {detail}", code);
|
||
|
|
}
|
||
|
|
}
|