about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2021-09-27 15:33:39 +0300
committerVika <vika@fireburn.ru>2021-09-27 15:33:39 +0300
commit1e204011e0e99de939475d4ce3b23b7b578f3b20 (patch)
tree92a1836237f2916ee44b31290532976c79f609f6
parent9203dd3ef7b62489116e7b7fe0b9d288c3389c78 (diff)
downloadkittybox-1e204011e0e99de939475d4ce3b23b7b578f3b20.tar.zst
Implemented FileStorage::get_setting and FileStorage::set_setting
-rw-r--r--Cargo.lock6
-rw-r--r--Cargo.toml1
-rw-r--r--src/database/file/mod.rs55
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(())
     }
 }