From 3f7624190bc02405cd44b75907db5c6ebfec8fd3 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Thu, 30 May 2024 23:46:05 +0200 Subject: [PATCH] Implement origin::fs --- src/main.rs | 17 ++++++++- src/origin.rs | 3 +- src/origin/fs.rs | 93 +++++++++++++++++++++++++++++++++++++++++++++++ src/origin/git.rs | 4 +- 4 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 src/origin/fs.rs diff --git a/src/main.rs b/src/main.rs index f233212..a1d58c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -103,7 +103,22 @@ async fn main() { ) } - let origin_store = domani::origin::git::Proxy::new(); + let origin_store = { + use domani::origin::*; + use std::sync::Arc; + + let git = git::Proxy::new(); + let fs = Arc::from(fs::new()); + + mux::new( + move |descr: &Descr| -> Option> { + match descr { + Descr::Git { .. } => Some(git.clone()), + Descr::FS { .. } => Some(fs.clone()), + } + }, + ) + }; let domain_checker = domani::domain::checker::DNSChecker::new( domani::token::MemStore::new(), diff --git a/src/origin.rs b/src/origin.rs index ad962d1..20481a6 100644 --- a/src/origin.rs +++ b/src/origin.rs @@ -1,4 +1,5 @@ pub mod descr; +pub mod fs; pub mod git; pub mod mux; @@ -22,7 +23,7 @@ pub enum SyncError { Unexpected(#[from] unexpected::Error), } -#[derive(thiserror::Error, Debug)] +#[derive(thiserror::Error, Debug, PartialEq)] pub enum GetFileError { #[error("descr not synced")] DescrNotSynced, diff --git a/src/origin/fs.rs b/src/origin/fs.rs new file mode 100644 index 0000000..53029dd --- /dev/null +++ b/src/origin/fs.rs @@ -0,0 +1,93 @@ +use crate::error::unexpected::{Intoable, Mappable}; +use crate::{origin, util}; +use std::path; + +#[derive(Clone)] +pub struct FS {} + +pub fn new() -> FS { + FS {} +} + +fn path_is_clean>(p: P) -> bool { + use path::Component; + for c in p.as_ref().components() { + match c { + Component::RootDir => (), + Component::Normal(_) => (), + _ => return false, + } + } + true +} + +impl origin::Store for FS { + fn sync(&self, _: &origin::Descr) -> util::BoxFuture<'_, Result<(), origin::SyncError>> { + Box::pin(futures::future::ready(Ok(()))) + } + + fn get_file( + &self, + descr: &origin::Descr, + path: &str, + ) -> util::BoxFuture<'_, Result> { + if !path_is_clean(path) { + return Box::pin(futures::future::ready(Err( + origin::GetFileError::FileNotFound, + ))); + } + + let descr = descr.clone(); + let path: path::PathBuf = path.to_string().into(); + Box::pin(async move { + let root_path = if let origin::descr::Descr::FS { path } = descr { + path + } else { + panic!("cannot deconstruct {descr:?} to FS") + }; + + let path = path + .strip_prefix("/") + .or_unexpected_while("relative path given to get_file")?; + + let path = root_path.as_ref().join(path); + + let f = tokio::fs::File::open(path).await.map_err(|e| { + use std::io::ErrorKind; + match e.kind() { + ErrorKind::NotFound => origin::GetFileError::FileNotFound, + _ => e.into_unexpected().into(), + } + })?; + + if f.metadata() + .await + .or_unexpected_while("getting file metadata")? + .is_dir() + { + return Err(origin::GetFileError::PathIsDirectory); + } + + Ok(util::BoxByteStream::from_async_read(f)) + }) + } +} + +#[cfg(test)] +mod fs_tests { + use super::*; + use crate::origin::{self, Store}; + + #[tokio::test] + async fn path_is_directory() { + let fs = new(); + let descr = origin::Descr::FS { + path: ".".parse().unwrap(), + }; + + assert_eq!( + origin::GetFileError::PathIsDirectory, + fs.get_file(&descr, "/src").await.err().unwrap(), + ) + } +} diff --git a/src/origin/git.rs b/src/origin/git.rs index c1a0363..de0f43d 100644 --- a/src/origin/git.rs +++ b/src/origin/git.rs @@ -33,8 +33,8 @@ pub struct Proxy { } impl Proxy { - pub fn new() -> Proxy { - Proxy::default() + pub fn new() -> sync::Arc { + sync::Arc::new(Proxy::default()) } fn deconstruct_descr(descr: &origin::Descr) -> (&origin::descr::GitUrl, &str) {