use std::time::Duration;
use iroh::{Endpoint, RelayMode, SecretKey, endpoint::ConnectionError};
use n0_snafu::ResultExt;
use n0_watcher::Watcher as _;
use tracing::{debug, info, warn};
const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/magic/0";
#[tokio::main]
async fn main() -> n0_snafu::Result<()> {
tracing_subscriber::fmt::init();
println!("\nlisten example!\n");
let secret_key = SecretKey::generate(rand::rngs::OsRng);
println!("public key: {}", secret_key.public());
let endpoint = Endpoint::builder()
.secret_key(secret_key)
.alpns(vec![EXAMPLE_ALPN.to_vec()])
.relay_mode(RelayMode::Default)
.bind()
.await?;
let me = endpoint.node_id();
println!("node id: {me}");
println!("node listening addresses:");
let local_addrs = endpoint
.direct_addresses()
.initialized()
.await
.into_iter()
.map(|addr| {
let addr = addr.addr.to_string();
println!("\t{addr}");
addr
})
.collect::<Vec<_>>()
.join(" ");
let relay_url = endpoint.home_relay().initialized().await;
println!("node relay server url: {relay_url}");
println!("\nin a separate terminal run:");
println!(
"\tcargo run --example connect -- --node-id {me} --addrs \"{local_addrs}\" --relay-url {relay_url}\n"
);
while let Some(incoming) = endpoint.accept().await {
let mut connecting = match incoming.accept() {
Ok(connecting) => connecting,
Err(err) => {
warn!("incoming connection failed: {err:#}");
continue;
}
};
let alpn = connecting.alpn().await?;
let conn = connecting.await.e()?;
let node_id = conn.remote_node_id()?;
info!(
"new connection from {node_id} with ALPN {}",
String::from_utf8_lossy(&alpn),
);
tokio::spawn(async move {
let (mut send, mut recv) = conn.accept_bi().await.e()?;
debug!("accepted bi stream, waiting for data...");
let message = recv.read_to_end(100).await.e()?;
let message = String::from_utf8(message).e()?;
println!("received: {message}");
let message = format!("hi! you connected to {me}. bye bye");
send.write_all(message.as_bytes()).await.e()?;
send.finish().e()?;
let res = tokio::time::timeout(Duration::from_secs(3), async move {
let closed = conn.closed().await;
if !matches!(closed, ConnectionError::ApplicationClosed(_)) {
println!("node {node_id} disconnected with an error: {closed:#}");
}
})
.await;
if res.is_err() {
println!("node {node_id} did not disconnect within 3 seconds");
}
Ok::<_, n0_snafu::Error>(())
});
}
Ok(())
}