git.delta.rocks / remowt / refs/commits / eadb0bb3c19e

difftreelog

source

crates/remowt-endpoints/src/fs.rs2.9 KiBsourcehistory
1use std::io::ErrorKind;2use std::str::FromStr;3use std::sync::Mutex;45use bifrostlink::declarative::endpoints;6use bifrostlink::Config;7use camino::Utf8PathBuf;8use serde::{Deserialize, Serialize};9use tempfile::TempDir;1011#[derive(Default)]12pub struct Fs {13	tempdirs: Mutex<Vec<TempDir>>,14}1516impl Fs {17	pub fn new() -> Self {18		Self::default()19	}20}2122#[derive(Serialize, Deserialize, Debug, thiserror::Error)]23pub enum Error {24	#[error("file not found")]25	NotFound,26	#[error("file name/contents is not utf8")]27	InvalidUtf8,28	#[error("unknown fs error")]29	Unknown,30}3132#[endpoints(ns = 1)]33impl Fs {34	#[endpoints(id = 1)]35	async fn read_file_tiny(&self, path: Utf8PathBuf) -> Result<Vec<u8>, Error> {36		match tokio::fs::read(path).await {37			Ok(v) => Ok(v),38			Err(e) if e.kind() == ErrorKind::NotFound => Err(Error::NotFound),39			_ => Err(Error::Unknown),40		}41	}42	#[endpoints(id = 2)]43	async fn file_exists(&self, path: Utf8PathBuf) -> bool {44		tokio::fs::try_exists(path).await.unwrap_or(false)45	}46	#[endpoints(id = 3)]47	async fn read_dir_raw(&self, path: Utf8PathBuf) -> Result<Vec<Utf8PathBuf>, Error> {48		let mut dir = match tokio::fs::read_dir(path).await {49			Ok(dir) => dir,50			Err(e) if e.kind() == ErrorKind::NotFound => return Err(Error::NotFound),51			Err(_) => return Err(Error::Unknown),52		};53		let mut out = Vec::new();54		while let Ok(Some(entry)) = dir.next_entry().await {55			let name = Utf8PathBuf::try_from(entry.file_name()).map_err(|_| Error::InvalidUtf8)?;56			out.push(name);57		}58		Ok(out)59	}60	#[endpoints(id = 4)]61	async fn mktemp_dir_raw(&self) -> Result<Utf8PathBuf, Error> {62		let dir = tempfile::Builder::new()63			.prefix("remowt.")64			.tempdir()65			.map_err(|_| Error::Unknown)?;66		let mut tempdirs = self.tempdirs.lock().expect("not poisoned");67		let path = Utf8PathBuf::try_from(dir.path().to_owned()).map_err(|_| Error::InvalidUtf8);68		tempdirs.push(dir);69		path70	}71	#[endpoints(id = 5)]72	async fn rm_file(&self, path: Utf8PathBuf) -> Result<(), Error> {73		match tokio::fs::remove_file(path).await {74			Ok(()) => Ok(()),75			Err(e) if e.kind() == ErrorKind::NotFound => Ok(()),76			Err(_) => Err(Error::Unknown),77		}78	}79}8081impl<C: Config> FsClient<C> {82	pub async fn read_file_text(&self, path: impl Into<Utf8PathBuf>) -> Result<String, Error> {83		let v = self84			.read_file_tiny(path.into())85			.await86			.map_err(|_| Error::Unknown)?;87		let v = v?;88		String::from_utf8(v).map_err(|_| Error::InvalidUtf8)89	}90	pub async fn read_file_value<T: FromStr>(91		&self,92		path: impl Into<Utf8PathBuf>,93	) -> Result<Result<T, T::Err>, Error> {94		let text = self.read_file_text(path).await?;95		Ok(T::from_str(&text))96	}97	pub async fn mktemp_dir(&self) -> Result<Utf8PathBuf, Error> {98		self.mktemp_dir_raw().await.map_err(|_| Error::Unknown)?99	}100	pub async fn read_dir(&self, path: impl Into<Utf8PathBuf>) -> Result<Vec<Utf8PathBuf>, Error> {101		self.read_dir_raw(path.into())102			.await103			.map_err(|_| Error::Unknown)?104	}105}