Skip to content

Commit

Permalink
Merge pull request #93 from eholk/happy-eyeballs
Browse files Browse the repository at this point in the history
Example: Happy eyeballs
  • Loading branch information
yoshuawuyts authored Nov 21, 2022
2 parents df3cc41 + 606a68c commit df53a89
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ pin-project = "1.0.8"
futures = "0.3.25"
futures-lite = "1.12.0"
criterion = { version = "0.3", features = ["async", "async_futures", "html_reports"] }
async-std = { version = "1.12.0", features = ["attributes"] }
futures-time = "3.0.0"
48 changes: 48 additions & 0 deletions examples/happy_eyeballs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use async_std::io::prelude::*;
use futures::future::TryFutureExt;
use futures_concurrency::prelude::*;
use futures_time::prelude::*;

use async_std::io;
use async_std::net::TcpStream;
use futures::channel::oneshot;
use futures_concurrency::vec::AggregateError;
use futures_time::time::Duration;
use std::error;

#[async_std::main]
async fn main() -> Result<(), Box<dyn error::Error + Send + Sync + 'static>> {
// Connect to a socket
let mut socket = open_tcp_socket("rust-lang.org", 80, 3).await?;

// Make an HTTP GET request.
socket.write_all(b"GET / \r\n").await?;
io::copy(&mut socket, &mut io::stdout()).await?;

Ok(())
}

/// Happy eyeballs algorithm!
async fn open_tcp_socket(
addr: &str,
port: u16,
attempts: u64,
) -> Result<TcpStream, AggregateError<io::Error>> {
let (mut sender, mut receiver) = oneshot::channel();
let mut futures = Vec::with_capacity(attempts as usize);

for attempt in 0..attempts {
// Start a next attempt if the previous one finishes, or timeout expires.
let tcp = TcpStream::connect((addr, port));
let start_event = receiver.timeout(Duration::from_secs(attempt));
futures.push(tcp.delay(start_event).map_err(|err| {
// If the socket fails, start the next attempt
let _ = sender.send(());
err
}));
(sender, receiver) = oneshot::channel();
}

// Start connecting. If an attempt succeeds, cancel all others attempts.
Ok(futures.race_ok().await?)
}

0 comments on commit df53a89

Please sign in to comment.