use rsb_derive::Builder;
use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::time::Duration;
use url::ParseError;
#[derive(Debug)]
pub enum SlackClientError {
ApiError(SlackClientApiError),
HttpError(SlackClientHttpError),
HttpProtocolError(SlackClientHttpProtocolError),
EndOfStream(SlackClientEndOfStreamError),
SystemError(SlackClientSystemError),
ProtocolError(SlackClientProtocolError),
FormUrlEncodingError(SlackClientFormUrlEncodingError),
SocketModeProtocolError(SlackClientSocketModeProtocolError),
RateLimitError(SlackRateLimitError),
}
impl SlackClientError {
fn option_to_string<T: ToString>(value: &Option<T>) -> String {
value
.as_ref()
.map_or_else(|| "-".to_string(), |v| v.to_string())
}
}
impl Display for SlackClientError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match *self {
SlackClientError::ApiError(ref err) => err.fmt(f),
SlackClientError::HttpError(ref err) => err.fmt(f),
SlackClientError::HttpProtocolError(ref err) => err.fmt(f),
SlackClientError::EndOfStream(ref err) => err.fmt(f),
SlackClientError::ProtocolError(ref err) => err.fmt(f),
SlackClientError::FormUrlEncodingError(ref err) => err.fmt(f),
SlackClientError::SocketModeProtocolError(ref err) => err.fmt(f),
SlackClientError::SystemError(ref err) => err.fmt(f),
SlackClientError::RateLimitError(ref err) => err.fmt(f),
}
}
}
impl Error for SlackClientError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
SlackClientError::ApiError(ref err) => Some(err),
SlackClientError::HttpError(ref err) => Some(err),
SlackClientError::HttpProtocolError(ref err) => Some(err),
SlackClientError::EndOfStream(ref err) => Some(err),
SlackClientError::ProtocolError(ref err) => Some(err),
SlackClientError::FormUrlEncodingError(ref err) => Some(err),
SlackClientError::SocketModeProtocolError(ref err) => Some(err),
SlackClientError::SystemError(ref err) => Some(err),
SlackClientError::RateLimitError(ref err) => Some(err),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Builder)]
pub struct SlackClientApiError {
pub code: String,
pub errors: Option<Vec<String>>,
pub warnings: Option<Vec<String>>,
pub http_response_body: Option<String>,
}
impl Display for SlackClientApiError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"Slack API error: {}\nBody: '{}'",
self.code,
SlackClientError::option_to_string(&self.http_response_body)
)
}
}
impl Error for SlackClientApiError {}
#[derive(Debug, PartialEq, Eq, Clone, Builder)]
pub struct SlackClientHttpError {
pub status_code: http::StatusCode,
pub http_response_body: Option<String>,
}
impl Display for SlackClientHttpError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"Slack HTTP error status: {}. Body: '{}'",
self.status_code,
SlackClientError::option_to_string(&self.http_response_body)
)
}
}
impl std::error::Error for SlackClientHttpError {}
#[derive(Debug, Builder)]
pub struct SlackClientHttpProtocolError {
pub cause: Option<Box<dyn std::error::Error + Sync + Send>>,
}
impl Display for SlackClientHttpProtocolError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "Slack http protocol error: {:?}", self.cause)
}
}
impl std::error::Error for SlackClientHttpProtocolError {}
#[derive(Debug, PartialEq, Eq, Clone, Builder)]
pub struct SlackClientEndOfStreamError {}
impl Display for SlackClientEndOfStreamError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "Slack end of stream error")
}
}
impl std::error::Error for SlackClientEndOfStreamError {}
#[derive(Debug, Builder)]
pub struct SlackClientProtocolError {
pub json_error: serde_json::Error,
pub json_body: Option<String>,
}
impl Display for SlackClientProtocolError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"Slack JSON protocol error: {}. Body: '{}'",
self.json_error,
SlackClientError::option_to_string(&self.json_body)
)
}
}
impl std::error::Error for SlackClientProtocolError {}
#[derive(Debug, Builder)]
pub struct SlackClientFormUrlEncodingError {
pub serialization_error: serde_urlencoded::ser::Error,
pub json_body: Option<String>,
}
impl Display for SlackClientFormUrlEncodingError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"Slack JSON to URL serialization protocol error: {}. Body: '{}'",
self.serialization_error,
SlackClientError::option_to_string(&self.json_body)
)
}
}
impl std::error::Error for SlackClientFormUrlEncodingError {}
#[derive(Debug, PartialEq, Eq, Clone, Builder)]
pub struct SlackClientSocketModeProtocolError {
pub message: String,
}
impl Display for SlackClientSocketModeProtocolError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "Slack socket mode protocol error: {}", self.message)
}
}
impl std::error::Error for SlackClientSocketModeProtocolError {}
#[derive(Debug, Builder)]
pub struct SlackClientSystemError {
pub message: Option<String>,
pub cause: Option<Box<dyn std::error::Error + Sync + Send + 'static>>,
}
impl Display for SlackClientSystemError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"Slack system protocol error. {}{:?}",
self.message.as_ref().unwrap_or(&"".to_string()),
self.cause
)
}
}
impl std::error::Error for SlackClientSystemError {}
#[derive(Debug, PartialEq, Eq, Clone, Builder)]
pub struct SlackRateLimitError {
pub retry_after: Option<Duration>,
pub code: Option<String>,
pub warnings: Option<Vec<String>>,
pub http_response_body: Option<String>,
}
impl Display for SlackRateLimitError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(
f,
"Slack API rate limit error: {}\nBody: '{}'. Retry after: `{:?}`",
SlackClientError::option_to_string(&self.code),
SlackClientError::option_to_string(&self.http_response_body),
self.retry_after,
)
}
}
impl Error for SlackRateLimitError {}
impl From<url::ParseError> for SlackClientError {
fn from(url_parse_error: ParseError) -> Self {
SlackClientError::HttpProtocolError(
SlackClientHttpProtocolError::new().with_cause(Box::new(url_parse_error)),
)
}
}
impl From<Box<dyn std::error::Error + Sync + Send>> for SlackClientError {
fn from(err: Box<dyn Error + Sync + Send>) -> Self {
SlackClientError::SystemError(SlackClientSystemError::new().with_cause(err))
}
}
pub fn map_serde_error(err: serde_json::Error, tried_to_parse: Option<&str>) -> SlackClientError {
SlackClientError::ProtocolError(
SlackClientProtocolError::new(err).opt_json_body(tried_to_parse.map(|s| s.to_string())),
)
}
pub fn map_serde_urlencoded_error(
err: serde_urlencoded::ser::Error,
tried_to_parse: Option<&str>,
) -> SlackClientError {
SlackClientError::FormUrlEncodingError(
SlackClientFormUrlEncodingError::new(err)
.opt_json_body(tried_to_parse.map(|s| s.to_string())),
)
}