use std::sync::Arc; use tonic::Status; use crate::status::{ConnectCode, ConnectStatus}; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("channel error: {0}")] ChannelError(#[source] anyhow::Error), #[error("codec error: {0}")] CodecError(#[source] anyhow::Error), #[error("invalid base64 data: {0}")] InvalidBase64(#[from] base64::DecodeError), #[error("invalid status code {0}")] InvalidCode(i32), #[error("invalid message codec: {0}")] InvalidMessageCodec(#[source] anyhow::Error), #[error("invalid request: {0}")] InvalidRequest(#[source] anyhow::Error), #[error("invalid response: {0}")] InvalidResponse(#[source] anyhow::Error), #[error("invalid status: {0}")] InvalidStatus(#[source] anyhow::Error), #[error("invalid stream frame: {0}")] InvalidStreamFrame(#[source] anyhow::Error), #[error("invalid timeout: {0}")] InvalidTimeout(#[source] anyhow::Error), #[error("need at least {0} more bytes")] NeedMoreData(usize), #[error("json error: {0}")] JsonError(#[from] serde_json::Error), #[error("protobuf decode error: {0}")] ProtoDecodeError(#[from] prost::DecodeError), #[error("protobuf encode error: {0}")] ProtoEncodeError(#[from] prost::EncodeError), #[error("{0}")] StatusError(#[from] tonic::Status), #[error("timed out")] TimedOut, #[error(transparent)] Other(anyhow::Error), } impl Error { pub fn status(code: ConnectCode, message: impl Into) -> Self { Self::StatusError(tonic::Status::new(code.into(), message)) } pub fn code(&self) -> ConnectCode { use Error::*; match self { TimedOut => ConnectCode::DeadlineExceeded, _ => ConnectCode::Internal, } } } impl From for ConnectStatus { fn from(err: Error) -> Self { if let Error::StatusError(status) = err { return Self::from_tonic_status_lenient(&status); } Self { code: err.code(), message: err.to_string(), details: vec![], } } } impl From for Status { fn from(err: Error) -> Self { let mut status = Status::new(err.code().into(), err.to_string()); status.set_source(Arc::new(err)); status } }