1use std::sync::{Arc, Mutex};23use bifrostlink::declarative::endpoints;4use bifrostlink::Config;5use camino::Utf8PathBuf;6use iroh::{Endpoint, EndpointId, SecretKey};7use remowt_link_shared::iroh_tunnel::{build_endpoint, TunnelDialer};8use serde::{Deserialize, Serialize};9use std::result::Result;10use tokio::net::UnixStream;11use tracing::{debug, warn};1213#[derive(Serialize, Deserialize, Debug, thiserror::Error)]14pub enum Error {15 #[error("iroh transport pipe unavailable: {0}")]16 Pipe(String),17 #[error("iroh endpoint failed: {0}")]18 Iroh(String),19}2021#[derive(Clone)]22pub struct IrohTunnel {23 dialer: Arc<TunnelDialer>,24 endpoint: Arc<Mutex<Option<Endpoint>>>,25}2627impl IrohTunnel {28 pub fn new(dialer: Arc<TunnelDialer>) -> Self {29 Self {30 dialer,31 endpoint: Arc::new(Mutex::new(None)),32 }33 }34}3536#[endpoints(ns = 11)]37impl IrohTunnel {38 #[endpoints(id = 1)]39 async fn setup(40 &self,41 client_id: EndpointId,42 xport_socket: Utf8PathBuf,43 ) -> Result<EndpointId, Error> {44 let stream = UnixStream::connect(&xport_socket)45 .await46 .map_err(|e| Error::Pipe(e.to_string()))?;4748 let secret = SecretKey::generate();49 let agent_id = secret.public();50 let ep = build_endpoint(secret, stream, client_id, true)51 .await52 .map_err(|e| Error::Iroh(e.to_string()))?;5354 let dialer = self.dialer.clone();55 let accept_ep = ep.clone();56 tokio::spawn(async move {57 while let Some(incoming) = accept_ep.accept().await {58 let dialer = dialer.clone();59 match incoming.accept() {60 Ok(accepting) => {61 tokio::spawn(async move {62 match accepting.await {63 Ok(conn) => {64 if conn.remote_id() != client_id {65 warn!("iroh: rejecting connection from unexpected peer");66 conn.close(0u32.into(), b"unexpected peer");67 return;68 }69 debug!("iroh tunnel connection accepted");70 dialer.set_conn(conn);71 }72 Err(e) => warn!("iroh accept failed: {e}"),73 }74 });75 }76 Err(e) => warn!("iroh incoming rejected: {e}"),77 }78 }79 });8081 *self.endpoint.lock().expect("not poisoned") = Some(ep);8283 Ok(agent_id)84 }85}