1use std::process::Stdio;2use std::sync::Arc;34use bifrostlink::Config;5use bifrostlink::declarative::endpoints;6use remowt_link_shared::iroh_tunnel::{TunnelAddr, TunnelDialer};7use serde::{Deserialize, Serialize};8use std::result::Result;9use tokio::io::{self, AsyncWriteExt as _};10use tokio::process::Command;1112#[derive(Clone)]13pub struct NixDaemon {14 dialer: Arc<TunnelDialer>,15}1617impl NixDaemon {18 pub fn new(dialer: Arc<TunnelDialer>) -> Self {19 Self { dialer }20 }21}2223#[derive(Serialize, Deserialize, Debug, thiserror::Error)]24pub enum Error {25 #[error("nix daemon unavailable: {0}")]26 DaemonUnavailable(String),27 #[error("tunnel socket unavailable: {0}")]28 Tunnel(String),29}3031#[endpoints(ns = 4)]32impl NixDaemon {33 #[endpoints(id = 2)]34 async fn serve_store(&self, store: String, tunnel: TunnelAddr) -> Result<(), Error> {35 let mut child = Command::new("nix-daemon")36 .arg("--stdio")37 .arg("--store")38 .arg(&store)39 .stdin(Stdio::piped())40 .stdout(Stdio::piped())41 .spawn()42 .map_err(|e| Error::DaemonUnavailable(e.to_string()))?;43 let tunnel = self44 .dialer45 .connect_tunnel(&tunnel)46 .await47 .map_err(|e| Error::Tunnel(e.to_string()))?;48 let mut stdin = child.stdin.take().expect("piped");49 let mut stdout = child.stdout.take().expect("piped");50 tokio::spawn(async move {51 let (mut tr, mut tw) = io::split(tunnel);52 let to_child = async {53 let _ = io::copy(&mut tr, &mut stdin).await;54 let _ = stdin.shutdown().await;55 };56 let from_child = async {57 let _ = io::copy(&mut stdout, &mut tw).await;58 let _ = tw.shutdown().await;59 };60 tokio::join!(to_child, from_child);61 let _ = child.wait().await;62 });63 Ok(())64 }65}