use std::sync::{
Arc,
atomic::{AtomicU64, Ordering},
};
use iroh::{
Endpoint, EndpointAddr,
endpoint::{Accepting, Connection, presets},
protocol::{AcceptError, ProtocolHandler, Router},
};
use n0_error::{Result, StdResultExt, e};
const ALPN: &[u8] = b"iroh-example/screening-connection/0";
#[tokio::main]
async fn main() -> Result<()> {
let router = start_accept_side().await?;
router.endpoint().online().await;
let endpoint_addr = router.endpoint().addr();
connect_side(&endpoint_addr).await?;
if let Err(err) = connect_side(&endpoint_addr).await {
println!("Error connecting: {}", err);
}
connect_side(&endpoint_addr).await?;
router.shutdown().await.anyerr()?;
Ok(())
}
async fn connect_side(addr: &EndpointAddr) -> Result<()> {
let endpoint = Endpoint::bind(presets::N0).await?;
let conn = endpoint.connect(addr.clone(), ALPN).await?;
let (mut send, mut recv) = conn.open_bi().await.anyerr()?;
send.write_all(b"Hello, world!").await.anyerr()?;
send.finish().anyerr()?;
let response = recv.read_to_end(1000).await.anyerr()?;
assert_eq!(&response, b"Hello, world!");
conn.close(0u32.into(), b"bye!");
endpoint.close().await;
Ok(())
}
async fn start_accept_side() -> Result<Router> {
let endpoint = Endpoint::bind(presets::N0).await?;
let echo = ScreenedEcho {
conn_attempt_count: Arc::new(AtomicU64::new(0)),
};
let router = Router::builder(endpoint).accept(ALPN, echo).spawn();
Ok(router)
}
#[derive(Debug, Clone)]
struct ScreenedEcho {
conn_attempt_count: Arc<AtomicU64>,
}
impl ProtocolHandler for ScreenedEcho {
async fn on_accepting(&self, accepting: Accepting) -> Result<Connection, AcceptError> {
self.conn_attempt_count.fetch_add(1, Ordering::Relaxed);
let count = self.conn_attempt_count.load(Ordering::Relaxed);
if count.is_multiple_of(2) {
println!("rejecting connection");
return Err(e!(AcceptError::NotAllowed));
}
let conn = accepting.await?;
Ok(conn)
}
async fn accept(&self, connection: Connection) -> Result<(), AcceptError> {
let endpoint_id = connection.remote_id();
println!("accepted connection from {endpoint_id}");
let (mut send, mut recv) = connection.accept_bi().await?;
let bytes_sent = tokio::io::copy(&mut recv, &mut send).await?;
println!("Copied over {bytes_sent} byte(s)");
send.finish()?;
connection.closed().await;
Ok(())
}
}