defmodule GRPC.RPCError do
@moduledoc """
The RPC error raised in server side and got in client side.
# server side
raise GRPC.RPCError, status: :unknown # preferred
raise GRPC.RPCError, status: GRPC.Status.unknown, message: "error message"
# client side
{:error, error} = Your.Stub.unary_call(channel, request)
"""
defexception [:status, :message, :details]
@type t :: %__MODULE__{status: GRPC.Status.t(), message: String.t(), details: list()}
alias GRPC.Status
@spec exception(Status.t(), String.t()) :: t
def new(status) when is_atom(status) do
exception(status: status)
end
def exception(args) when is_list(args) do
error = parse_args(args, %__MODULE__{})
if error.message do
error
else
Map.put(error, :message, status_message(error.status))
end
end
defp parse_args([], acc), do: acc
defp parse_args([{:status, status} | t], acc) when is_integer(status) do
acc = %{acc | status: status}
parse_args(t, acc)
end
defp parse_args([{:status, status} | t], acc) when is_atom(status) do
acc = %{acc | status: apply(GRPC.Status, status, [])}
parse_args(t, acc)
end
defp parse_args([{:message, message} | t], acc) when is_binary(message) do
acc = %{acc | message: message}
parse_args(t, acc)
end
defp parse_args([{:details, details} | t], acc) when is_list(details) do
acc = %{acc | details: details}
parse_args(t, acc)
end
def exception(status, message) when is_atom(status) do
%GRPC.RPCError{status: apply(GRPC.Status, status, []), message: message}
end
def exception(status, message) when is_integer(status) do
%GRPC.RPCError{status: status, message: message}
end
def exception(status, message, details) when is_atom(status) do
%GRPC.RPCError{status: apply(GRPC.Status, status, []), message: message, details: details}
end
def exception(status, message, details) when is_integer(status) do
%GRPC.RPCError{status: status, message: message, details: details}
end
defp status_message(1), do: "The operation was cancelled (typically by the caller)"
defp status_message(2), do: "Unknown error"
defp status_message(3), do: "Client specified an invalid argument"
defp status_message(4), do: "Deadline expired before operation could complete"
defp status_message(5), do: "Some requested entity (e.g., file or directory) was not found"
defp status_message(6),
do: "Some entity that we attempted to create (e.g., file or directory) already exists"
defp status_message(7),
do: "The caller does not have permission to execute the specified operation"
defp status_message(8), do: "Some resource has been exhausted"
defp status_message(9),
do:
"Operation was rejected because the system is not in a state required for the operation's execution"
defp status_message(10), do: "The operation was aborted"
defp status_message(11), do: "Operation was attempted past the valid range"
defp status_message(12),
do: "Operation is not implemented or not supported/enabled in this service"
defp status_message(13), do: "Internal errors"
defp status_message(14), do: "The service is currently unavailable"
defp status_message(15), do: "Unrecoverable data loss or corruption"
defp status_message(16),
do: "The request does not have valid authentication credentials for the operation"
end