use anyhow::ensure;
use iroh::endpoint::VarInt;
use iroh::{
endpoint::Connection, Endpoint, EndpointAddr, EndpointId, RelayMode, RelayUrl, SecretKey,
TransportAddr,
};
use pigdef::config::HardwareConfigMessage::Disconnect;
use pigdef::config::{HardwareConfig, HardwareConfigMessage};
use pigdef::description::HardwareDescription;
use pigdef::net_values::PIGGLET_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(
endpoint_id: &EndpointId,
relay: &Option<RelayUrl>,
) -> anyhow::Result<(HardwareDescription, HardwareConfig, Connection)> {
let secret_key = SecretKey::generate(&mut rand::rng());
let endpoint = Endpoint::builder()
.secret_key(secret_key)
.alpns(vec![PIGGLET_ALPN.to_vec()])
.relay_mode(RelayMode::Default)
.bind()
.await?;
endpoint.online().await;
let relay_url = relay
.clone()
.unwrap_or(endpoint.addr().relay_urls().next().unwrap().clone());
let addr = EndpointAddr::from_parts(*endpoint_id, vec![TransportAddr::Relay(relay_url)]);
let connection = endpoint.connect(addr, PIGGLET_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?;
connection.close(VarInt::from_u32(0u32), "disconnect".as_bytes());
Ok(())
}