use anyhow::{ensure, Context};
use iroh::{
endpoint::Connection,
RelayMode, RelayUrl, SecretKey, {Endpoint, NodeAddr, NodeId},
};
use pigdef::config::HardwareConfigMessage::Disconnect;
use pigdef::config::{HardwareConfig, HardwareConfigMessage};
use pigdef::description::HardwareDescription;
use pigdef::net_values::PIGLET_ALPN;
use std::io;
pub async fn wait_for_remote_message(
connection: &mut Connection,
) -> Result<HardwareConfigMessage, anyhow::Error> {
let mut config_receiver = connection.accept_uni().await?;
let message = config_receiver.read_to_end(4096).await?;
ensure!(
!message.is_empty(),
io::Error::new(io::ErrorKind::BrokenPipe, "Connection closed")
);
Ok(postcard::from_bytes(&message)?)
}
pub async fn send_config_message(
connection: &mut Connection,
config_change_message: &HardwareConfigMessage,
) -> anyhow::Result<()> {
let mut config_sender = connection.open_uni().await?;
let content = postcard::to_allocvec(&config_change_message)?;
config_sender.write_all(&content).await?;
config_sender.finish()?;
Ok(())
}
pub async fn connect(
nodeid: &NodeId,
relay: Option<RelayUrl>,
) -> anyhow::Result<(HardwareDescription, HardwareConfig, Connection)> {
let rng = rand::rngs::OsRng;
let secret_key = SecretKey::generate(rng);
let endpoint = Endpoint::builder()
.secret_key(secret_key)
.alpns(vec![PIGLET_ALPN.to_vec()])
.relay_mode(RelayMode::Default)
.bind()
.await?;
let _local_addrs = endpoint
.direct_addresses()
.initialized()
.await
.context("no endpoints")?
.into_iter()
.map(|endpoint| endpoint.addr.to_string())
.collect::<Vec<_>>()
.join(" ");
let relay_url = relay.unwrap_or(endpoint.home_relay().initialized().await?);
let addr = NodeAddr::from_parts(*nodeid, Some(relay_url), vec![]);
let connection = endpoint.connect(addr, PIGLET_ALPN).await?;
let mut gui_receiver = connection.accept_uni().await?;
let message = gui_receiver.read_to_end(4096).await?;
let reply: (HardwareDescription, HardwareConfig) = postcard::from_bytes(&message)?;
Ok((reply.0, reply.1, connection))
}
pub async fn disconnect(connection: &mut Connection) -> anyhow::Result<()> {
send_config_message(connection, &Disconnect).await
}