use aion_proto::{ProtoWireError, WireError};
use prost::Message;
use tonic::{Code, Status};
pub(crate) fn status_from_wire_error(error: WireError) -> Status {
status_with_code(grpc_code(error.code), error)
}
pub(crate) fn status_with_code(code: Code, error: WireError) -> Status {
let message = error.message.clone();
let mut details = Vec::new();
let proto_error = ProtoWireError::from(error);
if proto_error.encode(&mut details).is_ok() {
Status::with_details(code, message, details.into())
} else {
Status::new(code, message)
}
}
fn grpc_code(code: aion_proto::WireErrorCode) -> Code {
match code {
aion_proto::WireErrorCode::NotFound => Code::NotFound,
aion_proto::WireErrorCode::NamespaceDenied
| aion_proto::WireErrorCode::DeployDenied
| aion_proto::WireErrorCode::GrantDenied => Code::PermissionDenied,
aion_proto::WireErrorCode::SequenceConflict | aion_proto::WireErrorCode::NotOwner => {
Code::Aborted
}
aion_proto::WireErrorCode::UnknownQuery | aion_proto::WireErrorCode::InvalidInput => {
Code::InvalidArgument
}
aion_proto::WireErrorCode::QueryTimeout => Code::DeadlineExceeded,
aion_proto::WireErrorCode::NotRunning
| aion_proto::WireErrorCode::VersionPinned
| aion_proto::WireErrorCode::InvalidState => Code::FailedPrecondition,
aion_proto::WireErrorCode::Lagged => Code::ResourceExhausted,
aion_proto::WireErrorCode::Backend | aion_proto::WireErrorCode::QueryFailed => {
Code::Internal
}
}
}
#[cfg(test)]
mod tests {
use aion_proto::WireErrorCode;
use tonic::Code;
use super::grpc_code;
#[test]
fn not_owner_wire_code_maps_to_retryable_aborted() {
assert_eq!(grpc_code(WireErrorCode::NotOwner), Code::Aborted);
}
#[test]
fn invalid_state_wire_code_maps_to_failed_precondition() {
assert_eq!(
grpc_code(WireErrorCode::InvalidState),
Code::FailedPrecondition
);
}
}