@@ -40,6 +40,7 @@ pub trait ResultExt {
type Ok;
fn log_err(self) -> Option<Self::Ok>;
+ fn warn_on_err(self) -> Option<Self::Ok>;
}
impl<T> ResultExt for anyhow::Result<T> {
@@ -54,12 +55,25 @@ impl<T> ResultExt for anyhow::Result<T> {
}
}
}
+
+ fn warn_on_err(self) -> Option<T> {
+ match self {
+ Ok(value) => Some(value),
+ Err(error) => {
+ log::warn!("{:?}", error);
+ None
+ }
+ }
+ }
}
pub trait TryFutureExt {
fn log_err(self) -> LogErrorFuture<Self>
where
Self: Sized;
+ fn warn_on_err(self) -> LogErrorFuture<Self>
+ where
+ Self: Sized;
}
impl<F, T> TryFutureExt for F
@@ -70,11 +84,18 @@ where
where
Self: Sized,
{
- LogErrorFuture(self)
+ LogErrorFuture(self, log::Level::Error)
+ }
+
+ fn warn_on_err(self) -> LogErrorFuture<Self>
+ where
+ Self: Sized,
+ {
+ LogErrorFuture(self, log::Level::Warn)
}
}
-pub struct LogErrorFuture<F>(F);
+pub struct LogErrorFuture<F>(F, log::Level);
impl<F, T> Future for LogErrorFuture<F>
where
@@ -83,9 +104,16 @@ where
type Output = Option<T>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ let level = self.1;
let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
match inner.poll(cx) {
- Poll::Ready(output) => Poll::Ready(output.log_err()),
+ Poll::Ready(output) => Poll::Ready(match output {
+ Ok(output) => Some(output),
+ Err(error) => {
+ log::log!(level, "{:?}", error);
+ None
+ }
+ }),
Poll::Pending => Poll::Pending,
}
}
@@ -209,7 +209,7 @@ impl User {
User {
id: message.id,
github_login: message.github_login,
- avatar: fetch_avatar(http, &message.avatar_url).log_err().await,
+ avatar: fetch_avatar(http, &message.avatar_url).warn_on_err().await,
}
}
}
@@ -257,6 +257,9 @@ async fn fetch_avatar(http: &dyn HttpClient, url: &str) -> Result<Arc<ImageData>
.send(request)
.await
.map_err(|e| anyhow!("failed to send user avatar request: {}", e))?;
+ if !response.status().is_success() {
+ return Err(anyhow!("avatar request failed {:?}", response.status()));
+ }
let bytes = response
.body_bytes()
.await