use std::{fmt::Display, net::SocketAddr};
use bytes::Bytes;
use reqwest::{Response, StatusCode};
use thiserror::Error;
use tokio::runtime::Handle;
#[derive(Error, Debug)]
pub struct NetworkError {
pub status_code: StatusCode,
pub origin_address: Option<SocketAddr>,
pub raw_body: Option<Bytes>,
}
impl Display for NetworkError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let body = self
.raw_body
.as_ref()
.map(|val| String::from_utf8(val.to_owned().to_vec()).ok())
.unwrap_or_default()
.unwrap_or_default();
write!(
f,
"Error -- Status: {}, Origin: {}, Body: {}",
self.status_code,
self.origin_address
.map(|socket| socket.to_string())
.unwrap_or_default(),
body
)
}
}
impl From<Response> for NetworkError {
fn from(res: Response) -> Self {
Self::new(res)
}
}
impl NetworkError {
fn new(response: Response) -> Self {
Self {
status_code: response.status(),
origin_address: response.remote_addr(),
raw_body: tokio::task::block_in_place(move || {
return Handle::current().block_on(async move {
return response.bytes().await.ok();
});
}),
}
}
}