git.delta.rocks / fleet / refs/commits / 48d120aa4aef

difftreelog

source

crates/remowt-fleet/src/lib.rs3.2 KiBsourcehistory
1use std::path::PathBuf;23use anyhow::{Context as _, Result};4use bifrostlink::declarative::endpoints;5use bifrostlink::Config;6use camino::Utf8PathBuf;7use nix_eval::eval_store;8use remowt_client::Remowt;9use remowt_endpoints::nix_daemon::NixDaemonClient;10use remowt_link_shared::iroh_tunnel::TunnelAddr;11use serde::{Deserialize, Serialize};12use tokio::net::UnixListener;13use tokio::task::spawn_blocking;14use tracing::error;1516pub struct Nix;17pub use nix_eval::{init_libraries, init_tokio_for_nix};1819#[derive(Serialize, Deserialize, Debug, thiserror::Error)]20pub enum NixError {21	#[error("nix daemon unavailable: {0}")]22	DaemonUnavailable(String),23	#[error("tunnel socket unavailable: {0}")]24	Tunnel(String),25	#[error("profile switch failed: {0}")]26	Profile(String),27	#[error("signing failed: {0}")]28	Sign(String),29	#[error("listing generations failed: {0}")]30	ListGenerations(String),31}3233#[endpoints(ns = 91)]34impl Nix {35	#[endpoints(id = 3)]36	async fn switch_profile(37		&self,38		profile: String,39		store_path: Utf8PathBuf,40	) -> Result<(), NixError> {41		let store = eval_store();42		spawn_blocking(move || store.switch_profile(&profile, &store_path))43			.await44			.expect("switch_profile panicked")45			.map_err(|e| NixError::Profile(e.to_string()))46	}4748	#[endpoints(id = 4)]49	async fn sign_closure(50		&self,51		store_path: Utf8PathBuf,52		key_file: Utf8PathBuf,53	) -> Result<(), NixError> {54		spawn_blocking(move || {55			let store = eval_store();56			store.sign_closure(&store_path, &key_file)57		})58		.await59		.expect("store signing panicked")60		.map_err(|e| NixError::Sign(e.to_string()))61	}6263	#[endpoints(id = 5)]64	async fn list_generations(65		&self,66		profile: String,67	) -> Result<Vec<nix_eval::ProfileGeneration>, NixError> {68		spawn_blocking(move || {69			nix_eval::list_generations(&format!("/nix/var/nix/profiles/{profile}"))70		})71		.await72		.expect("generation listing panicked")73		.map_err(|e| NixError::ListGenerations(e.to_string()))74	}75}7677pub async fn nix_store_socket(conn: Remowt, store: &str) -> Result<PathBuf> {78	let store = store.to_owned();79	let path = std::env::temp_dir().join(format!("fleet-nix-{}.sock", uuid::Uuid::new_v4()));80	let _ = std::fs::remove_file(&path);81	let listener = UnixListener::bind(&path)?;82	tokio::spawn(async move {83		if let Err(e) = serve(conn, listener, store).await {84			error!("nix daemon proxy failed: {e}");85		}86	});87	Ok(path)88}8990async fn serve(conn: Remowt, listener: UnixListener, store: String) -> Result<()> {91	let nix = conn.endpoints::<NixDaemonClient<_>>();92	loop {93		let (mut local, _) = listener.accept().await?;9495		let (rx, remote_sock) = match conn.bind_runtime_unix("nix-daemon").await {96			Ok(rx) => rx,97			Err(e) => {98				error!("streamlocal_forward failed: {e}");99				continue;100			}101		};102		match nix103			.serve_store(store.clone(), TunnelAddr::Unix(remote_sock))104			.await105		{106			Ok(Ok(())) => {}107			Ok(Err(e)) => {108				error!("nix bridge: {e}");109				continue;110			}111			Err(e) => {112				error!("nix bridge rpc failed: {e}");113				continue;114			}115		}116117		let mut channel = rx118			.accept()119			.await120			.context("failed to accept remote nix connection")?;121		tokio::spawn(async move {122			if let Err(e) = tokio::io::copy_bidirectional(&mut local, &mut channel).await {123				tracing::debug!("nix tunnel ended: {e}");124			}125		});126	}127}