1use std::process::Stdio;2use std::sync::Arc;34use bifrostlink::declarative::endpoints;5use bifrostlink::Config;6use remowt_link_shared::iroh_tunnel::{TunnelAddr, TunnelDialer};7use serde::{Deserialize, Serialize};8use std::result::Result;9use tokio::process::Command;1011#[derive(Clone)]12pub struct NixDaemon {13 dialer: Arc<TunnelDialer>,14}1516impl NixDaemon {17 pub fn new(dialer: Arc<TunnelDialer>) -> Self {18 Self { dialer }19 }20}2122#[derive(Serialize, Deserialize, Debug, thiserror::Error)]23pub enum Error {24 #[error("nix daemon unavailable: {0}")]25 DaemonUnavailable(String),26 #[error("tunnel socket unavailable: {0}")]27 Tunnel(String),28}2930#[endpoints(ns = 4)]31impl NixDaemon {32 #[endpoints(id = 2)]33 async fn serve_store(&self, store: String, tunnel: TunnelAddr) -> Result<(), Error> {34 let mut child = Command::new("nix-daemon")35 .arg("--stdio")36 .arg("--store")37 .arg(&store)38 .stdin(Stdio::piped())39 .stdout(Stdio::piped())40 .spawn()41 .map_err(|e| Error::DaemonUnavailable(e.to_string()))?;42 let tunnel = self43 .dialer44 .connect_tunnel(&tunnel)45 .await46 .map_err(|e| Error::Tunnel(e.to_string()))?;47 let mut stdin = child.stdin.take().expect("piped");48 let mut stdout = child.stdout.take().expect("piped");49 tokio::spawn(async move {50 let (mut tr, mut tw) = tokio::io::split(tunnel);51 let _ = tokio::join!(52 tokio::io::copy(&mut tr, &mut stdin),53 tokio::io::copy(&mut stdout, &mut tw),54 );55 let _ = child.wait().await;56 });57 Ok(())58 }59}