1use std::process::Stdio;23use bifrostlink::declarative::endpoints;4use bifrostlink::Config;5use serde::{Deserialize, Serialize};6use std::result::Result;7use tokio::process::Command;89pub const NIX_DAEMON_SOCKET: &str = "/nix/var/nix/daemon-socket/socket";1011pub struct NixDaemon;1213#[derive(Serialize, Deserialize, Debug, thiserror::Error)]14pub enum Error {15 #[error("nix daemon unavailable: {0}")]16 DaemonUnavailable(String),17 #[error("tunnel socket unavailable: {0}")]18 Tunnel(String),19}2021#[endpoints(ns = 4)]22impl NixDaemon {23 #[endpoints(id = 1)]24 async fn connect_daemon(&self, socket: String) -> Result<(), Error> {25 let mut daemon = tokio::net::UnixStream::connect(NIX_DAEMON_SOCKET)26 .await27 .map_err(|e| Error::DaemonUnavailable(e.to_string()))?;28 let mut tunnel = tokio::net::UnixStream::connect(&socket)29 .await30 .map_err(|e| Error::Tunnel(e.to_string()))?;31 tokio::spawn(async move {32 if let Err(e) = tokio::io::copy_bidirectional(&mut daemon, &mut tunnel).await {33 tracing::debug!("nix daemon tunnel ended: {e}");34 }35 });36 Ok(())37 }3839 #[endpoints(id = 2)]40 async fn serve_store(&self, store: String, socket: String) -> Result<(), Error> {41 let mut child = Command::new("nix-daemon")42 .arg("--stdio")43 .arg("--store")44 .arg(&store)45 .stdin(Stdio::piped())46 .stdout(Stdio::piped())47 .spawn()48 .map_err(|e| Error::DaemonUnavailable(e.to_string()))?;49 let tunnel = tokio::net::UnixStream::connect(&socket)50 .await51 .map_err(|e| Error::Tunnel(e.to_string()))?;52 let mut stdin = child.stdin.take().expect("piped");53 let mut stdout = child.stdout.take().expect("piped");54 tokio::spawn(async move {55 let mut tunnel = tunnel;56 let (mut tr, mut tw) = tunnel.split();57 let _ = tokio::join!(58 tokio::io::copy(&mut tr, &mut stdin),59 tokio::io::copy(&mut stdout, &mut tw),60 );61 let _ = child.wait().await;62 });63 Ok(())64 }65}