Skip to content

Commit

Permalink
Use MaybeFuture
Browse files Browse the repository at this point in the history
  • Loading branch information
flub committed Dec 12, 2024
1 parent d800104 commit a6678ca
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 13 deletions.
22 changes: 11 additions & 11 deletions iroh/src/magicsock/relay_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use std::{
use anyhow::Context;
use backoff::backoff::Backoff;
use bytes::{Bytes, BytesMut};
use futures_lite::future;
use futures_util::future::Either;
use iroh_metrics::{inc, inc_by};
use iroh_relay::{self as relay, client::ClientError, ReceivedMessage, RelayUrl, MAX_PACKET_SIZE};
use tokio::{
Expand All @@ -28,6 +26,7 @@ use tracing::{debug, error, info, info_span, trace, warn, Instrument};
use crate::{
key::{NodeId, PUBLIC_KEY_LENGTH},
magicsock::{MagicSock, Metrics as MagicsockMetrics, RelayContents, RelayDatagramsQueue},
util::MaybeFuture,
};

/// How long a non-home relay connection needs to be idle (last written to) before we close it.
Expand Down Expand Up @@ -113,11 +112,10 @@ impl ConnectedRelayActor {
let relay_client = self.relay_client.clone();
relay_client.connect().await.context("initial connection")?;

// When this future is Either::Right this is a future which is currently sending
// When this future has an inner, it is a future which is currently sending
// something to the relay server. Nothing else can be sent to the relay server at
// the same time. If this future is Either::Left nothing is being sent to the
// relay server.
let mut relay_send_fut = Either::Left(future::pending());
// the same time.
let mut relay_send_fut = MaybeFuture::none();

loop {
// If a read error occurred on the connection it might have been lost. But we
Expand All @@ -137,13 +135,15 @@ impl ConnectedRelayActor {
break;
}
}
// Only poll relay_send_fut if it is sending to the future.
_ = &mut relay_send_fut, if matches!(relay_send_fut, Either::Right(_)) => {
relay_send_fut = Either::Left(future::pending());
// Only poll relay_send_fut if it is sending to the relay.
_ = &mut relay_send_fut, if relay_send_fut.is_some() => {
relay_send_fut = MaybeFuture::none();
}
// Only poll for new datagrams if relay_send_fut is not busy.
Some(msg) = self.relay_datagrams_send.recv(), if matches!(relay_send_fut, Either::Left(_)) => {
relay_send_fut = Either::Right(Box::pin(relay_client.send(msg.0, msg.1)));
Some(msg) = self.relay_datagrams_send.recv(), if relay_send_fut.is_none() => {
relay_send_fut = MaybeFuture::with_future(
Box::pin(relay_client.send(msg.0, msg.1))
);
self.last_write = Instant::now();

}
Expand Down
31 changes: 29 additions & 2 deletions iroh/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,44 @@ use std::{
task::{Context, Poll},
};

/// Resolves to pending if the inner is `None`.
/// A future which may not be present.
///
/// This is a single type which may optionally contain a future. If there is no inner
/// future polling will always return [`Poll::Pending`].
///
/// The [`Default`] impl will create a [`MaybeFuture`] without an inner.
#[derive(Debug)]
pub(crate) struct MaybeFuture<T> {
/// Future to be polled.
pub inner: Option<T>,
}

impl<T> MaybeFuture<T> {
/// Creates a [`MaybeFuture`] without an inner future.
pub(crate) fn none() -> Self {
Self { inner: None }
}

/// Creates a [`MaybeFuture`] with an inner future.
pub(crate) fn with_future(fut: T) -> Self {
Self { inner: Some(fut) }
}

/// Returns `true` if the inner is empty.
pub(crate) fn is_none(&self) -> bool {
self.inner.is_none()
}

/// Returns `true` if the inner contains a future.
pub(crate) fn is_some(&self) -> bool {
self.inner.is_some()
}
}

// NOTE: explicit implementation to bypass derive unnecessary bounds
impl<T> Default for MaybeFuture<T> {
fn default() -> Self {
MaybeFuture { inner: None }
Self::none()
}
}

Expand Down

0 comments on commit a6678ca

Please sign in to comment.