use std::fmt::{Display, Formatter};
use std::string::FromUtf8Error;
use hyper::StatusCode;
use crate::imp::api::DockerEngineApiBuilderError;
use crate::errors::DecLibraryError;
use crate::model::StreamLineReadError;
use crate::imp::http_proxy::DockerEngineResponseNotUtf8;
#[derive(Debug)]
pub enum DecUseError {
ApiNotFound {
uri: String
},
ApiNotImplemented {
uri: String
},
HttpClientError(hyper::Error),
Internal(DecLibraryError),
NotFound {
message: String
},
StreamLineRead(StreamLineReadError),
Rejected {
status: StatusCode,
message: String
},
UnexpectedResponseContentType {
expected: String,
actual: Option<String>
},
UnparseableJsonResponse {
status: StatusCode,
text: String,
parse_error: serde_json::error::Error
},
UnparseableUtf8Response {
status: StatusCode,
content_type: Option<String>,
parse_error: FromUtf8Error
},
}
impl DecUseError {
pub fn error_message(&self) -> String {
match self {
Self::ApiNotFound { uri } =>
format!("Api not found at {}", uri),
Self::ApiNotImplemented { uri } =>
format!("Api not implemented at {}", uri),
Self::Internal(internal) =>
internal.message(),
Self::NotFound { message } =>
message.clone(),
Self::Rejected { status, message } =>
format!("Request rejected with HTTP status: {}: {}", status, message),
Self::StreamLineRead(error) =>
error.error_message(),
Self::UnparseableJsonResponse { status, text, parse_error} =>
format!("Response with status {} had unparseable JSON: {}; response below:\n{}", status, parse_error, text),
Self::UnparseableUtf8Response { status, content_type, parse_error } =>
format!(
"Response with status {} and {} not parseable as UTF-8: {}",
status,
match content_type {
None => "no content type".into(),
Some(ct) => format!("content type {}", ct)
},
parse_error
),
Self::HttpClientError(hyper_error) =>
format!("Response error: {}", hyper_error),
Self::UnexpectedResponseContentType { expected, actual } =>
format!(
"Expected response Content-Type of {} but {}",
expected,
match actual {
None =>
"header was missing".to_string(),
Some(a) =>
format!("received {}", a)
}
)
}
}
pub fn from_not_utf8(other: DockerEngineResponseNotUtf8) -> Self {
Self::UnparseableUtf8Response {
status: other.status,
content_type: other.content_type,
parse_error: other.error
}
}
}
impl Display for DecUseError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.error_message())
}
}
impl From<DecLibraryError> for DecUseError {
fn from(other: DecLibraryError) -> Self {
Self::Internal(other)
}
}
impl From<DockerEngineApiBuilderError> for DecUseError {
fn from(other: DockerEngineApiBuilderError) -> Self {
DecLibraryError::from(other).into()
}
}
impl From<StreamLineReadError> for DecUseError {
fn from(other: StreamLineReadError) -> Self {
Self::StreamLineRead(other)
}
}
impl From<url::ParseError> for DecUseError {
fn from(other: url::ParseError) -> Self {
DecLibraryError::from(other).into()
}
}
#[cfg(test)]
mod test_error_message_and_display {
use crate::errors::DecUseError;
#[test]
pub fn response_content_type_missing() {
let error = DecUseError::UnexpectedResponseContentType {
expected: "foo".into(),
actual: None
};
let actual = format!("{}", error);
assert_eq!("Expected response Content-Type of foo but header was missing".to_string(), actual);
}
#[test]
pub fn response_content_type_wrong() {
let error = DecUseError::UnexpectedResponseContentType {
expected: "bar".into(),
actual: Some("qux".into())
};
let actual = format!("{}", error);
assert_eq!("Expected response Content-Type of bar but received qux".to_string(), actual);
}
}