use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[allow(dead_code)]
crate type GenericError = Box<dyn std::error::Error + Send + Sync>;
#[derive(Debug)]
pub struct Error {
code: ErrCode,
reason: String,
description: String,
source: Option<ErrSource>,
}
impl Error {
fn new<U>(code: ErrCode, reason: U, source: Option<ErrSource>) -> Self
where
U: Into<String>,
{
let reason = reason.into();
let code_str: &str = code.into();
let description = format!("{}: {}", code_str, reason.clone());
Self {
code,
reason,
description,
source,
}
}
crate fn digest_error() -> Self {
Self::new(ErrCode::Server, "message body digest does not match", None)
}
#[allow(dead_code)]
crate fn invalid_message_digest() -> Self {
Self::new(ErrCode::Server, "invalid message digest", None)
}
crate fn invalid_message_id() -> Self {
Self::new(ErrCode::Server, "invalid message id", None)
}
crate fn publish_error() -> Self {
Self::new(ErrCode::Server, "unable to publish order", None)
}
}
impl std::error::Error for Error {
#[must_use]
fn description(&self) -> &str {
&self.description
}
#[must_use]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if let Some(ref x) = self.source {
Some(x)
} else {
None
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use std::error::Error;
let res = std::error::Error::iter_sources(self).fold(
self.description().to_string(),
|mut s, e| {
s.push_str(&format!(" => {}", e));
s
},
);
write!(f, "{}", res)
}
}
impl From<&str> for Error {
#[must_use]
fn from(text: &str) -> Self {
let split = text.split(':');
let vec = split.collect::<Vec<&str>>();
let code = vec.get(0).unwrap_or_else(|| &"");
let reason = vec.get(1).unwrap_or_else(|| &"");
Self::new((*code).into(), *reason, None)
}
}
#[derive(Copy, Clone, Debug)]
crate enum ErrCode {
Client,
Env,
Framework,
HttpClient,
Io,
Parse,
Server,
Unknown,
}
impl Into<&str> for ErrCode {
#[must_use]
fn into(self) -> &'static str {
match self {
Self::Client => "client",
Self::Env => "env",
Self::Framework => "framework",
Self::HttpClient => "httpclient",
Self::Io => "io",
Self::Parse => "parse",
Self::Server => "server",
Self::Unknown => "unknown",
}
}
}
impl Into<String> for ErrCode {
#[must_use]
fn into(self) -> String {
let tmp: &str = self.into();
tmp.to_string()
}
}
impl From<&str> for ErrCode {
#[must_use]
fn from(text: &str) -> Self {
match text {
"client" => Self::Client,
"env" => Self::Env,
"framework" => Self::Framework,
"httpclient" => Self::HttpClient,
"io" => Self::Io,
"parse" => Self::Parse,
"server" => Self::Server,
_ => Self::Unknown,
}
}
}
macro_rules! dep_error {
($error:ty, $kind:expr, $code:expr, $reason:expr) => {
impl From<$error> for Error {
#[must_use]
fn from(inner: $error) -> Self {
Self::new($code, $reason, Some($kind(inner)))
}
}
};
}
dep_error!(
http::Error,
ErrSource::Http,
ErrCode::Server,
"There was an error processing an HTTP request"
);
dep_error!(
http::uri::InvalidUri,
ErrSource::InvalidUri,
ErrCode::Parse,
"There was an error parsing a URI"
);
dep_error!(
hyper::Error,
ErrSource::Hyper,
ErrCode::Framework,
"There was an error with the hyper server"
);
dep_error!(
hyper_tls::Error,
ErrSource::HyperTls,
ErrCode::Framework,
"There was an error setting up an HTTPS connection"
);
dep_error!(
rusoto_core::RusotoError<rusoto_sqs::DeleteMessageError>,
ErrSource::DeleteMessage,
ErrCode::Framework,
"There was an error deleting the message from the queue"
);
dep_error!(
rusoto_core::RusotoError<rusoto_sqs::GetQueueUrlError>,
ErrSource::GetQueueUrl,
ErrCode::Framework,
"There was an error getting the queue url"
);
dep_error!(
rusoto_core::RusotoError<rusoto_sqs::ReceiveMessageError>,
ErrSource::ReceiveMessage,
ErrCode::Framework,
"There was an error receiving a message from the queue"
);
dep_error!(
rusoto_core::RusotoError<rusoto_sqs::SendMessageError>,
ErrSource::SendMessage,
ErrCode::Framework,
"There was an error sending a message to the queue"
);
dep_error!(
rusoto_credential::CredentialsError,
ErrSource::Credentials,
ErrCode::Client,
"There was an error determining your credentials"
);
dep_error!(
std::io::Error,
ErrSource::Io,
ErrCode::Io,
"There was an error processing your request"
);
dep_error!(
std::net::AddrParseError,
ErrSource::AddrParse,
ErrCode::Parse,
"There was an error parsing the socket address"
);
dep_error!(
std::string::FromUtf8Error,
ErrSource::FromUtf8,
ErrCode::Parse,
"There was an error involving a non UTF-8 string"
);
dep_error!(
log::SetLoggerError,
ErrSource::SetLogger,
ErrCode::Framework,
"There was an error setting up the logger"
);
dep_error!(
serde_json::Error,
ErrSource::SerdeJson,
ErrCode::Parse,
"There was an error converting JSON"
);
dep_error!(
uuid::Error,
ErrSource::Uuid,
ErrCode::Parse,
"There was an error parsing a UUID"
);
#[derive(Debug)]
#[allow(variant_size_differences)]
crate enum ErrSource {
AddrParse(std::net::AddrParseError),
Credentials(rusoto_credential::CredentialsError),
DeleteMessage(rusoto_core::RusotoError<rusoto_sqs::DeleteMessageError>),
FromUtf8(std::string::FromUtf8Error),
GetQueueUrl(rusoto_core::RusotoError<rusoto_sqs::GetQueueUrlError>),
Http(http::Error),
Hyper(hyper::Error),
HyperTls(hyper_tls::Error),
InvalidUri(http::uri::InvalidUri),
Io(std::io::Error),
ReceiveMessage(rusoto_core::RusotoError<rusoto_sqs::ReceiveMessageError>),
SendMessage(rusoto_core::RusotoError<rusoto_sqs::SendMessageError>),
SerdeJson(serde_json::Error),
SetLogger(log::SetLoggerError),
Uuid(uuid::Error),
}
impl std::error::Error for ErrSource {
#[must_use]
fn description(&self) -> &str {
match self {
Self::AddrParse(source) => source.description(),
Self::Credentials(source) => source.description(),
Self::DeleteMessage(source) => source.description(),
Self::FromUtf8(source) => source.description(),
Self::GetQueueUrl(source) => source.description(),
Self::Http(source) => source.description(),
Self::Hyper(source) => source.description(),
Self::HyperTls(source) => source.description(),
Self::InvalidUri(source) => source.description(),
Self::Io(source) => source.description(),
Self::ReceiveMessage(source) => source.description(),
Self::SendMessage(source) => source.description(),
Self::SerdeJson(source) => source.description(),
Self::SetLogger(_source) => "error setting logger",
Self::Uuid(source) => source.description(),
}
}
}
impl fmt::Display for ErrSource {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AddrParse(source) => write!(f, "{:?}", source),
Self::Credentials(source) => write!(f, "{:?}", source),
Self::DeleteMessage(source) => write!(f, "{:?}", source),
Self::FromUtf8(source) => write!(f, "{:?}", source),
Self::GetQueueUrl(source) => write!(f, "{:?}", source),
Self::Http(source) => write!(f, "{:?}", source),
Self::Hyper(source) => write!(f, "{}", source),
Self::HyperTls(source) => write!(f, "{}", source),
Self::InvalidUri(source) => write!(f, "{}", source),
Self::Io(source) => write!(f, "{}", source),
Self::ReceiveMessage(source) => write!(f, "{}", source),
Self::SendMessage(source) => write!(f, "{}", source),
Self::SerdeJson(source) => write!(f, "{}", source),
Self::SetLogger(source) => write!(f, "{}", source),
Self::Uuid(source) => write!(f, "{}", source),
}
}
}