use std::io;
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("Server Error: {0}")]
Server(String),
#[error("Task Database Error: {0}")]
Database(String),
#[error("Local replica is out of sync with the server")]
OutOfSync,
#[error("Usage Error: {0}")]
Usage(String),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
macro_rules! other_error {
( $error:ty ) => {
impl From<$error> for Error {
fn from(err: $error) -> Self {
Self::Other(err.into())
}
}
};
}
other_error!(io::Error);
other_error!(serde_json::Error);
other_error!(rusqlite::Error);
other_error!(crate::storage::sqlite::SqliteError);
#[cfg(feature = "server-gcp")]
other_error!(google_cloud_storage::http::Error);
#[cfg(feature = "server-gcp")]
other_error!(google_cloud_storage::client::google_cloud_auth::error::Error);
#[cfg(feature = "server-aws")]
other_error!(aws_sdk_s3::Error);
#[cfg(feature = "server-aws")]
other_error!(aws_sdk_s3::primitives::ByteStreamError);
#[cfg(feature = "server-sync")]
impl From<ureq::Error> for Error {
fn from(ureq_err: ureq::Error) -> Self {
match ureq_err {
ureq::Error::Status(status, response) => {
let msg = format!(
"{} responded with {} {}",
response.get_url(),
status,
response.status_text()
);
Self::Server(msg)
}
ureq::Error::Transport(_) => Self::Server(ureq_err.to_string()),
}
}
}
pub(crate) type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod test {
use super::*;
#[cfg(feature = "server-sync")]
#[test]
fn ureq_error_status() {
let err = ureq::Error::Status(
418,
ureq::Response::new(418, "I Am a Teapot", "uhoh").unwrap(),
);
assert_eq!(
Error::from(err).to_string(),
"Server Error: https://example.com/ responded with 418 I Am a Teapot"
);
}
}