use std::{
fmt::{self, Display, Formatter},
io, string,
};
use tokio::io::AsyncRead;
use super::{
binary::TAsyncBinaryProtocol, Message, Size, TFieldIdentifier, TInputProtocol, TLengthProtocol,
TOutputProtocol, TStructIdentifier, TType,
};
const TAPPLICATION_EXCEPTION: TStructIdentifier = TStructIdentifier {
name: "TApplicationException",
};
const ERROR_MESSAGE_FIELD: TFieldIdentifier = TFieldIdentifier {
name: Some("message"),
field_type: TType::String,
id: Some(1),
};
const ERROR_TYPE_FIELD: TFieldIdentifier = TFieldIdentifier {
name: Some("type"),
field_type: TType::I32,
id: Some(2),
};
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ApplicationErrorKind {
Unknown = 0,
UnknownMethod = 1,
InvalidMessageType = 2,
WrongMethodName = 3,
BadSequenceId = 4,
MissingResult = 5,
InternalError = 6,
ProtocolError = 7,
InvalidTransform = 8, InvalidProtocol = 9, UnsupportedClientType = 10, }
impl Display for ApplicationError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error_text = match self.kind {
ApplicationErrorKind::Unknown => "service error",
ApplicationErrorKind::UnknownMethod => "unknown service method",
ApplicationErrorKind::InvalidMessageType => "wrong message type received",
ApplicationErrorKind::WrongMethodName => "unknown method reply received",
ApplicationErrorKind::BadSequenceId => "out of order sequence id",
ApplicationErrorKind::MissingResult => "missing method result",
ApplicationErrorKind::InternalError => "remote service threw exception",
ApplicationErrorKind::ProtocolError => "protocol error",
ApplicationErrorKind::InvalidTransform => "invalid transform",
ApplicationErrorKind::InvalidProtocol => "invalid protocol requested",
ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client",
};
write!(f, "{}, msg: {}", error_text, self.message)
}
}
impl TryFrom<i32> for ApplicationErrorKind {
type Error = Error;
fn try_from(from: i32) -> Result<Self, Self::Error> {
match from {
0 => Ok(ApplicationErrorKind::Unknown),
1 => Ok(ApplicationErrorKind::UnknownMethod),
2 => Ok(ApplicationErrorKind::InvalidMessageType),
3 => Ok(ApplicationErrorKind::WrongMethodName),
4 => Ok(ApplicationErrorKind::BadSequenceId),
5 => Ok(ApplicationErrorKind::MissingResult),
6 => Ok(ApplicationErrorKind::InternalError),
7 => Ok(ApplicationErrorKind::ProtocolError),
8 => Ok(ApplicationErrorKind::InvalidTransform),
9 => Ok(ApplicationErrorKind::InvalidProtocol),
10 => Ok(ApplicationErrorKind::UnsupportedClientType),
_ => Err(Error::Application(ApplicationError {
kind: ApplicationErrorKind::Unknown,
message: format!("cannot convert {} to ApplicationErrorKind", from),
})),
}
}
}
pub fn new_application_error<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> Error {
Error::Application(ApplicationError::new(kind, message))
}
impl Display for ProtocolError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error_text = match self.kind {
ProtocolErrorKind::Unknown => "protocol error",
ProtocolErrorKind::InvalidData => "bad data",
ProtocolErrorKind::NegativeSize => "negative message size",
ProtocolErrorKind::SizeLimit => "message too long",
ProtocolErrorKind::BadVersion => "invalid thrift version",
ProtocolErrorKind::NotImplemented => "not implemented",
ProtocolErrorKind::DepthLimit => "maximum skip depth reached",
};
write!(f, "{}, {}", error_text, self.message)
}
}
impl TryFrom<i32> for ProtocolErrorKind {
type Error = Error;
fn try_from(from: i32) -> Result<Self, Self::Error> {
match from {
0 => Ok(ProtocolErrorKind::Unknown),
1 => Ok(ProtocolErrorKind::InvalidData),
2 => Ok(ProtocolErrorKind::NegativeSize),
3 => Ok(ProtocolErrorKind::SizeLimit),
4 => Ok(ProtocolErrorKind::BadVersion),
5 => Ok(ProtocolErrorKind::NotImplemented),
6 => Ok(ProtocolErrorKind::DepthLimit),
_ => Err(Error::Protocol(ProtocolError {
kind: ProtocolErrorKind::Unknown,
message: format!("cannot convert {} to ProtocolErrorKind", from),
})),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ApplicationError {
pub kind: ApplicationErrorKind,
pub message: String,
}
impl ApplicationError {
pub fn new<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> ApplicationError {
ApplicationError {
kind,
message: message.into(),
}
}
}
pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error {
Error::Transport(TransportError::new(kind, message))
}
#[non_exhaustive]
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub enum TransportErrorKind {
Unknown = 0,
NotOpen = 1,
AlreadyOpen = 2,
TimedOut = 3,
EndOfFile = 4,
NegativeSize = 5,
SizeLimit = 6,
}
impl Display for TransportError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let error_text = match self.kind {
TransportErrorKind::Unknown => "transport error",
TransportErrorKind::NotOpen => "not open",
TransportErrorKind::AlreadyOpen => "already open",
TransportErrorKind::TimedOut => "timed out",
TransportErrorKind::EndOfFile => "end of file",
TransportErrorKind::NegativeSize => "negative size message",
TransportErrorKind::SizeLimit => "message too long",
};
write!(f, "{} because {}", error_text, self.message)
}
}
impl TryFrom<i32> for TransportErrorKind {
type Error = Error;
fn try_from(from: i32) -> Result<Self, Self::Error> {
match from {
0 => Ok(TransportErrorKind::Unknown),
1 => Ok(TransportErrorKind::NotOpen),
2 => Ok(TransportErrorKind::AlreadyOpen),
3 => Ok(TransportErrorKind::TimedOut),
4 => Ok(TransportErrorKind::EndOfFile),
5 => Ok(TransportErrorKind::NegativeSize),
6 => Ok(TransportErrorKind::SizeLimit),
_ => Err(Error::Protocol(ProtocolError {
kind: ProtocolErrorKind::Unknown,
message: format!("cannot convert {} to TransportErrorKind", from),
})),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct TransportError {
pub kind: TransportErrorKind,
pub message: String,
}
impl TransportError {
pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError {
TransportError {
kind,
message: message.into(),
}
}
}
#[derive(Debug)]
pub enum Error {
Transport(TransportError),
Protocol(ProtocolError),
Application(ApplicationError),
}
impl From<TransportError> for Error {
fn from(e: TransportError) -> Self {
Error::Transport(e)
}
}
impl From<ProtocolError> for Error {
fn from(e: ProtocolError) -> Self {
Error::Protocol(e)
}
}
impl From<ApplicationError> for Error {
fn from(e: ApplicationError) -> Self {
Error::Application(e)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
match err.kind() {
io::ErrorKind::ConnectionReset
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::NotConnected => Error::Transport(TransportError {
kind: TransportErrorKind::NotOpen,
message: err.to_string(),
}),
io::ErrorKind::AlreadyExists => Error::Transport(TransportError {
kind: TransportErrorKind::AlreadyOpen,
message: err.to_string(),
}),
io::ErrorKind::TimedOut => Error::Transport(TransportError {
kind: TransportErrorKind::TimedOut,
message: err.to_string(),
}),
io::ErrorKind::UnexpectedEof => Error::Transport(TransportError {
kind: TransportErrorKind::EndOfFile,
message: err.to_string(),
}),
_ => {
Error::Transport(TransportError {
kind: TransportErrorKind::Unknown,
message: err.to_string(), })
}
}
}
}
impl From<string::FromUtf8Error> for Error {
fn from(err: string::FromUtf8Error) -> Self {
Error::Protocol(ProtocolError {
kind: ProtocolErrorKind::InvalidData,
message: err.to_string(), })
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ProtocolError {
pub kind: ProtocolErrorKind,
pub message: String,
}
impl ProtocolError {
pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
ProtocolError {
kind,
message: message.into(),
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub enum ProtocolErrorKind {
Unknown = 0,
InvalidData = 1,
NegativeSize = 2,
SizeLimit = 3,
BadVersion = 4,
NotImplemented = 5,
DepthLimit = 6,
}
pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> Error {
Error::Protocol(ProtocolError::new(kind, message))
}
impl From<Box<dyn std::error::Error + Send + Sync>> for Error {
fn from(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
new_application_error(ApplicationErrorKind::Unknown, err.to_string())
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for Error {}
#[async_trait::async_trait]
impl Message for ApplicationError {
fn encode<T: TOutputProtocol>(&self, protocol: &mut T) -> Result<(), Error> {
protocol.write_struct_begin(&TAPPLICATION_EXCEPTION)?;
protocol.write_field_begin(&ERROR_MESSAGE_FIELD)?;
protocol.write_string(&self.message)?;
protocol.write_field_end()?;
protocol.write_field_begin(&ERROR_TYPE_FIELD)?;
protocol.write_i32(self.kind as i32)?;
protocol.write_field_end()?;
protocol.write_field_stop()?;
protocol.write_struct_end()?;
protocol.flush()?;
Ok(())
}
fn decode<T: TInputProtocol>(protocol: &mut T) -> Result<Self, Error> {
let mut message = "general remote error".to_owned();
let mut kind = ApplicationErrorKind::Unknown;
protocol.read_struct_begin()?;
loop {
let field_ident = protocol.read_field_begin()?;
if field_ident.field_type == TType::Stop {
break;
}
let id = field_ident
.id
.expect("sender should always specify id for non-STOP field");
match id {
1 => {
let remote_message = protocol.read_string()?;
protocol.read_field_end()?;
message = (&*remote_message).into();
}
2 => {
let remote_type_as_int = protocol.read_i32()?;
let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int)
.unwrap_or(ApplicationErrorKind::Unknown);
protocol.read_field_end()?;
kind = remote_kind;
}
_ => {
protocol.skip(field_ident.field_type)?;
}
}
}
protocol.read_struct_end()?;
Ok(ApplicationError { kind, message })
}
async fn decode_async<R>(protocol: &mut TAsyncBinaryProtocol<R>) -> Result<Self, Error>
where
R: AsyncRead + Unpin + Send,
{
let mut message = "general remote error".to_owned();
let mut kind = ApplicationErrorKind::Unknown;
protocol.read_struct_begin().await?;
loop {
let field_ident = protocol.read_field_begin().await?;
if field_ident.field_type == TType::Stop {
break;
}
let id = field_ident
.id
.expect("sender should always specify id for non-STOP field");
match id {
1 => {
let remote_message = protocol.read_string().await?;
protocol.read_field_end().await?;
message = (&*remote_message).into();
}
2 => {
let remote_type_as_int = protocol.read_i32().await?;
let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int)
.unwrap_or(ApplicationErrorKind::Unknown);
protocol.read_field_end().await?;
kind = remote_kind;
}
_ => {
protocol.skip(field_ident.field_type).await?;
}
}
}
protocol.read_struct_end().await?;
Ok(ApplicationError { kind, message })
}
}
impl Size for ApplicationError {
fn size<T: TLengthProtocol>(&self, protocol: &T) -> usize {
protocol.write_struct_begin_len(&TAPPLICATION_EXCEPTION)
+ protocol.write_field_begin_len(&ERROR_MESSAGE_FIELD)
+ protocol.write_string_len(&self.message)
+ protocol.write_field_end_len()
+ protocol.write_field_begin_len(&ERROR_TYPE_FIELD)
+ protocol.write_i32_len(self.kind as i32)
+ protocol.write_field_end_len()
+ protocol.write_field_stop_len()
+ protocol.write_struct_end_len()
}
}
#[derive(Debug, thiserror::Error)]
pub enum UserError<T> {
#[error("a exception from remote: {0}")]
UserException(T),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
#[derive(Debug, thiserror::Error)]
pub enum ResponseError<T> {
#[error("a exception from remote: {0}")]
UserException(T),
#[error("application error: {0}")]
Application(ApplicationError),
#[error("transport error: {0}")]
Transport(TransportError),
#[error("protocol error: {0}")]
Protocol(ProtocolError),
}
impl<T> From<Error> for ResponseError<T> {
fn from(e: Error) -> Self {
match e {
Error::Transport(e) => ResponseError::Transport(e),
Error::Protocol(e) => ResponseError::Protocol(e),
Error::Application(e) => ResponseError::Application(e),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct DummyError;
#[async_trait::async_trait]
impl Message for DummyError {
fn encode<T: TOutputProtocol>(&self, _protocol: &mut T) -> Result<(), Error> {
panic!()
}
fn decode<T: TInputProtocol>(_protocol: &mut T) -> Result<Self, Error> {
panic!()
}
async fn decode_async<R>(_protocol: &mut TAsyncBinaryProtocol<R>) -> Result<Self, Error>
where
R: AsyncRead + Unpin + Send,
{
panic!()
}
}
impl Size for DummyError {
fn size<T: TLengthProtocol>(&self, _protocol: &T) -> usize {
panic!()
}
}