diff --git a/zebrad/src/components/inbound.rs b/zebrad/src/components/inbound.rs index e200fb21..2ee22474 100644 --- a/zebrad/src/components/inbound.rs +++ b/zebrad/src/components/inbound.rs @@ -10,6 +10,7 @@ use futures::{ future::{FutureExt, TryFutureExt}, stream::Stream, }; +use oneshot::error::TryRecvError; use tokio::sync::oneshot; use tower::{buffer::Buffer, timeout::Timeout, util::BoxService, Service, ServiceExt}; @@ -72,9 +73,17 @@ pub enum Setup { /// /// We keep hold of the closed oneshot, so we can use it to create a /// new error for each `poll_ready` call. - FailedRecv { - failed_setup: oneshot::Receiver, - }, + FailedRecv { error: SharedRecvError }, +} + +#[derive(thiserror::Error, Debug, Clone)] +#[error(transparent)] +pub struct SharedRecvError(Arc); + +impl From for SharedRecvError { + fn from(source: TryRecvError) -> Self { + Self(Arc::new(source)) + } } /// Uses the node state to respond to inbound peer requests. @@ -131,8 +140,6 @@ impl Service for Inbound { Pin> + Send + 'static>>; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - use oneshot::error::TryRecvError; - // Check whether the network setup is finished, but don't wait for it to // become ready before reporting readiness. We expect to get it "soon", // and reporting unreadiness might cause unwanted load-shedding, since @@ -169,8 +176,9 @@ impl Service for Inbound { Err(error @ TryRecvError::Closed) => { // Mark the service as failed, because network setup failed error!(?error, "inbound network setup failed"); + let error: SharedRecvError = error.into(); self.network = Setup::FailedRecv { - failed_setup: network_setup, + error: error.clone(), }; return Poll::Ready(Err(error.into())); } @@ -187,27 +195,8 @@ impl Service for Inbound { } // If network setup failed, report service failure - if let Setup::FailedRecv { failed_setup } = &mut self.network { - // TryRecvError is not cloneable, so we have to generate a new error from the oneshot, - // rather than re-using a clone of the original error - let failed_response = failed_setup.try_recv(); - match failed_response { - Err(error @ TryRecvError::Closed) => { - return Poll::Ready(Err(error.into())); - } - Err(error) => { - unreachable!( - "unexpected error kind from failed Inbound network setup oneshot: {:?}", - error - ); - } - Ok(_) => { - // we can't log the response, because it doesn't impl Debug - unreachable!( - "unexpected success response from failed Inbound network setup oneshot" - ); - } - } + if let Setup::FailedRecv { error } = &mut self.network { + return Poll::Ready(Err(error.clone().into())); } // Clean up completed download tasks, ignoring their results