diff options
Diffstat (limited to 'filamento/src/files.rs')
-rw-r--r-- | filamento/src/files.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/filamento/src/files.rs b/filamento/src/files.rs new file mode 100644 index 0000000..dcc9cd2 --- /dev/null +++ b/filamento/src/files.rs @@ -0,0 +1,143 @@ +use std::{ + collections::HashMap, + convert::Infallible, + error::Error, + path::{Path, PathBuf}, + sync::Arc, +}; + +use tokio::io; +use tokio::sync::Mutex; + +#[cfg(not(target_arch = "wasm32"))] +pub trait FileStore { + type Err: Clone + Send + Error; + + fn is_stored( + &self, + name: &str, + ) -> impl std::future::Future<Output = Result<bool, Self::Err>> + std::marker::Send; + fn store( + &self, + name: &str, + data: &[u8], + ) -> impl std::future::Future<Output = Result<(), Self::Err>> + std::marker::Send; + fn delete( + &self, + name: &str, + ) -> impl std::future::Future<Output = Result<(), Self::Err>> + std::marker::Send; +} + +#[cfg(target_arch = "wasm32")] +pub trait FileStore { + type Err: Clone + Send + Error; + + fn is_stored(&self, name: &str) -> impl std::future::Future<Output = Result<bool, Self::Err>>; + fn store( + &self, + name: &str, + data: &[u8], + ) -> impl std::future::Future<Output = Result<(), Self::Err>>; + fn delete(&self, name: &str) -> impl std::future::Future<Output = Result<(), Self::Err>>; +} + +#[derive(Clone, Debug)] +pub struct FilesMem { + files: Arc<Mutex<HashMap<String, Vec<u8>>>>, +} + +impl FilesMem { + pub fn new() -> Self { + Self { + files: Arc::new(Mutex::new(HashMap::new())), + } + } + + pub async fn get_file(&self, name: impl AsRef<str>) -> Option<Vec<u8>> { + let name = name.as_ref(); + self.files.lock().await.get(name).cloned() + } +} + +#[cfg(all(feature = "opfs", target_arch = "wasm32"))] +pub mod opfs; + +#[cfg(all(feature = "opfs", target_arch = "wasm32"))] +pub use opfs::FilesOPFS; + +impl FileStore for FilesMem { + type Err = Infallible; + + async fn is_stored(&self, name: &str) -> Result<bool, Self::Err> { + Ok(self.files.lock().await.contains_key(name)) + } + + async fn store(&self, name: &str, data: &[u8]) -> Result<(), Self::Err> { + self.files + .lock() + .await + .insert(name.to_string(), data.to_owned()); + + Ok(()) + } + + async fn delete(&self, name: &str) -> Result<(), Self::Err> { + self.files.lock().await.remove(name); + Ok(()) + } +} + +#[cfg(not(target_arch = "wasm32"))] +#[derive(Clone, Debug)] +pub struct Files { + root: PathBuf, +} + +#[cfg(not(target_arch = "wasm32"))] +impl Files { + pub fn new(root: impl AsRef<Path>) -> Self { + let root = root.as_ref(); + let root = root.into(); + Self { root } + } + + pub fn root(&self) -> &Path { + &self.root + } +} + +#[cfg(not(target_arch = "wasm32"))] +impl FileStore for Files { + type Err = Arc<io::Error>; + + async fn is_stored(&self, name: &str) -> Result<bool, Self::Err> { + tracing::debug!("checking if {} is stored", name); + // TODO: is this secure ;-; + let name = name.replace("/", "").replace(".", ""); + let res = tokio::fs::try_exists(self.root.join(name)) + .await + .map_err(|err| Arc::new(err)); + tracing::debug!("file check res: {:?}", res); + res + } + + async fn store(&self, name: &str, data: &[u8]) -> Result<(), Self::Err> { + tracing::debug!("storing {} is stored", name); + let name = name.replace("/", "").replace(".", ""); + let res = tokio::fs::write(self.root.join(name), data) + .await + .map_err(|err| Arc::new(err)); + tracing::debug!("file store res: {:?}", res); + res + } + + async fn delete(&self, name: &str) -> Result<(), Self::Err> { + tracing::debug!("deleting {}", name); + let name = name.replace("/", "").replace(".", ""); + let res = tokio::fs::remove_file(self.root.join(name)) + .await + .map_err(|err| Arc::new(err)); + tracing::debug!("file delete res: {:?}", res); + res + } +} |