difftreelog
feat remowt-nix-daemon
in: trunk
2 files changed
crates/remowt-nix-daemon/Cargo.tomldiffbeforeafterboth1[package]2name = "fleet-nix-daemon"3description = "Nix daemon proxy endpoint + connection logic for fleet"4version.workspace = true5edition = "2021"67[dependencies]8anyhow.workspace = true9bifrostlink.workspace = true10bifrostlink-macros.workspace = true11camino.workspace = true12remowt-client.workspace = true13serde = { workspace = true }14thiserror.workspace = true15tokio = { workspace = true, features = ["net", "io-util", "rt", "process"] }16tracing.workspace = true17uuid.workspace = truecrates/remowt-nix-daemon/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/remowt-nix-daemon/src/lib.rs
@@ -0,0 +1,65 @@
+use std::process::Stdio;
+
+use bifrostlink::declarative::endpoints;
+use bifrostlink::Config;
+use serde::{Deserialize, Serialize};
+use std::result::Result;
+use tokio::process::Command;
+
+pub const NIX_DAEMON_SOCKET: &str = "/nix/var/nix/daemon-socket/socket";
+
+pub struct NixDaemon;
+
+#[derive(Serialize, Deserialize, Debug, thiserror::Error)]
+pub enum Error {
+ #[error("nix daemon unavailable: {0}")]
+ DaemonUnavailable(String),
+ #[error("tunnel socket unavailable: {0}")]
+ Tunnel(String),
+}
+
+#[endpoints(ns = 4)]
+impl NixDaemon {
+ #[endpoints(id = 1)]
+ async fn connect_daemon(&self, socket: String) -> Result<(), Error> {
+ let mut daemon = tokio::net::UnixStream::connect(NIX_DAEMON_SOCKET)
+ .await
+ .map_err(|e| Error::DaemonUnavailable(e.to_string()))?;
+ let mut tunnel = tokio::net::UnixStream::connect(&socket)
+ .await
+ .map_err(|e| Error::Tunnel(e.to_string()))?;
+ tokio::spawn(async move {
+ if let Err(e) = tokio::io::copy_bidirectional(&mut daemon, &mut tunnel).await {
+ tracing::debug!("nix daemon tunnel ended: {e}");
+ }
+ });
+ Ok(())
+ }
+
+ #[endpoints(id = 2)]
+ async fn serve_store(&self, store: String, socket: String) -> Result<(), Error> {
+ let mut child = Command::new("nix-daemon")
+ .arg("--stdio")
+ .arg("--store")
+ .arg(&store)
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()
+ .map_err(|e| Error::DaemonUnavailable(e.to_string()))?;
+ let tunnel = tokio::net::UnixStream::connect(&socket)
+ .await
+ .map_err(|e| Error::Tunnel(e.to_string()))?;
+ let mut stdin = child.stdin.take().expect("piped");
+ let mut stdout = child.stdout.take().expect("piped");
+ tokio::spawn(async move {
+ let mut tunnel = tunnel;
+ let (mut tr, mut tw) = tunnel.split();
+ let _ = tokio::join!(
+ tokio::io::copy(&mut tr, &mut stdin),
+ tokio::io::copy(&mut stdout, &mut tw),
+ );
+ let _ = child.wait().await;
+ });
+ Ok(())
+ }
+}