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

difftreelog

source

remowt/cmds/remowt-agent/src/editor.rs2.4 KiBsourcehistory
1use std::env::{current_dir, temp_dir};2use std::path::Path;3use std::time::Duration;4use std::{fs, io};56use anyhow::{anyhow, bail, Context as _};7use bifrostlink::declarative::RemoteEndpoints as _;8use nix::libc;9use remowt_link_shared::editor::EditorEndpointsClient;10use remowt_link_shared::{gateway, Address, BifConfig};11use tokio::process::Command;1213pub async fn forward(udp: bool, addr: String) -> anyhow::Result<()> {14	let rpc = gateway::connect(&gateway::socket_path()?).await?;15	let editor = EditorEndpointsClient::<BifConfig>::wrap(rpc.remote(Address::User));16	let local = if udp {17		editor.expose_udp(addr).await18	} else {19		editor.expose_tcp(addr).await20	}21	.map_err(|e| anyhow!("requesting forward on the User: {e}"))?22	.map_err(|e| anyhow!("forward failed: {e}"))?;23	println!("{local}");24	Ok(())25}2627pub async fn edit(path: String) -> anyhow::Result<()> {28	let path = Path::new(&path);29	let abs = if path.is_absolute() {30		path.to_path_buf()31	} else {32		current_dir()?.join(path)33	};3435	let sock = temp_dir().join(format!("remowt-nvim-{}.sock", uuid::Uuid::new_v4()));36	let sock_str = sock37		.to_str()38		.context("temp socket path is not utf-8")?39		.to_owned();4041	let mut child = Command::new("nvim");42	child43		.arg("--headless")44		.arg("--listen")45		.arg(&sock)46		.arg("--")47		.arg(&abs)48		.kill_on_drop(true);49	// SAFETY: only an async-signal-safe `prctl` call.50	unsafe {51		child.pre_exec(|| {52			if libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL as libc::c_ulong) != 0 {53				return Err(io::Error::last_os_error());54			}55			Ok(())56		});57	}58	let mut child = child.spawn().context("spawning nvim")?;5960	wait_for_socket(&sock)61		.await62		.context("nvim did not start its server")?;6364	let rpc = gateway::connect(&gateway::socket_path()?).await?;65	let editor = EditorEndpointsClient::<BifConfig>::wrap(rpc.remote(Address::User));66	let result = editor67		.open_editor(sock_str)68		.await69		.map_err(|e| anyhow!("requesting editor on the User: {e}"))70		.and_then(|r| r.map_err(|e| anyhow!("editor failed: {e}")));7172	if tokio::time::timeout(Duration::from_secs(2), child.wait())73		.await74		.is_err()75	{76		let _ = child.kill().await;77	}78	let _ = fs::remove_file(&sock);7980	result81}8283async fn wait_for_socket(path: &Path) -> anyhow::Result<()> {84	for _ in 0..200 {85		if tokio::fs::try_exists(path).await.unwrap_or(false) {86			return Ok(());87		}88		tokio::time::sleep(Duration::from_millis(50)).await;89	}90	bail!("timed out waiting for {}", path.display())91}