diff options
-rw-r--r-- | Cargo.lock | 6 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/database/file/mod.rs | 55 |
3 files changed, 60 insertions, 2 deletions
diff --git a/Cargo.lock b/Cargo.lock index b6ce993..e4db2d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2025,6 +2025,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] +name = "relative-path" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9629de8974fd69c97684736786b807edd3da456d3e3f95341dd9d4cbd8f5ad6" + +[[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 3f93407..66e9043 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ retainer = "^0.2.2" # Minimal async cache in Rust with support for key serde_json = "^1.0.64" # A JSON serialization file format serde_urlencoded = "^0.7.0" # `x-www-form-urlencoded` meets Serde tide = "^0.16.0" # A minimal and pragmatic Rust web application framework built for rapid development +relative-path = "^1.5.0" # Portable relative paths for Rust [dependencies.anyhow] version = "^1.0.42" optional = true diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs index ff5ad13..d641779 100644 --- a/src/database/file/mod.rs +++ b/src/database/file/mod.rs @@ -261,10 +261,61 @@ impl Storage for FileStorage { } async fn get_setting<'a>(&self, setting: &'a str, user: &'a str) -> Result<String> { - todo!() + let url = http_types::Url::parse(user).expect("Couldn't parse a URL"); + let mut path = relative_path::RelativePathBuf::new(); + path.push(url.origin().ascii_serialization()); + path.push("settings"); + + let path = path.to_path(&self.root_dir); + let lock = get_lockable_file(File::open(path).await?).await; + let guard = lock.read()?; + + let mut content = String::new(); + (&mut &*guard).read_to_string(&mut content).await?; + drop(guard); + let settings: HashMap<String, String> = serde_json::from_str(&content)?; + // XXX consider returning string slices instead of cloning a string every time + // it might come with a performance hit and/or memory usage inflation + settings.get(setting) + .map(|s| s.clone()) + .ok_or_else(|| StorageError::new(ErrorKind::Backend, "Setting not set")) + } async fn set_setting<'a>(&self, setting: &'a str, user: &'a str, value: &'a str) -> Result<()> { - todo!() + let url = http_types::Url::parse(user).expect("Couldn't parse a URL"); + let mut path = relative_path::RelativePathBuf::new(); + path.push(url.origin().ascii_serialization()); + path.push("settings"); + + let path = path.to_path(&self.root_dir); + + let parent = path.parent().unwrap().to_owned(); + if !spawn_blocking(move || parent.is_dir()).await { + async_std::fs::create_dir_all(path.parent().unwrap()).await?; + } + + let file = OpenOptions::new() + .write(true) + .read(true) + .truncate(false) + .create(true) + .open(&path).await?; + let mut lock = get_lockable_file(file).await; + let mut guard = lock.write()?; + + let mut content = String::new(); + guard.read_to_string(&mut content).await?; + let mut settings: HashMap<String, String> = if content.len() == 0 { + HashMap::default() + } else { + serde_json::from_str(&content)? + }; + + settings.insert(setting.to_string(), value.to_string()); + guard.seek(std::io::SeekFrom::Start(0)).await?; + guard.set_len(0).await?; + guard.write_all(serde_json::to_string(&settings)?.as_bytes()).await?; + Ok(()) } } |