summaryrefslogtreecommitdiff
path: root/shared/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-13 15:23:50 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-13 15:23:50 +0100
commitfffd27abb3b3e1cbe0a4236ee68be5bf6588a20c (patch)
treee1dce8d7b554eaf46b772cb016eaf89aa210c7e1 /shared/src
parentf8f94eb194fe8a4db5c7120596f64d2a864fe823 (diff)
downloadweareserver-fffd27abb3b3e1cbe0a4236ee68be5bf6588a20c.tar
weareserver-fffd27abb3b3e1cbe0a4236ee68be5bf6588a20c.tar.bz2
weareserver-fffd27abb3b3e1cbe0a4236ee68be5bf6588a20c.tar.zst
filesystem resource cache
Diffstat (limited to 'shared/src')
-rw-r--r--shared/src/store.rs61
1 files changed, 59 insertions, 2 deletions
diff --git a/shared/src/store.rs b/shared/src/store.rs
index 673a40e..08e62be 100644
--- a/shared/src/store.rs
+++ b/shared/src/store.rs
@@ -16,21 +16,51 @@
*/
use crate::{helper::ReadWrite, packets::Resource};
use anyhow::Result;
+use log::info;
use redb::{Database, TableDefinition};
-use std::{collections::HashMap, marker::PhantomData, path::Path, sync::Mutex};
+use std::{
+ collections::HashMap,
+ env::var,
+ fs::{File, create_dir_all, rename},
+ io::{Read, Write},
+ marker::PhantomData,
+ path::{Path, PathBuf},
+ sync::Mutex,
+};
const T_ENTRIES: TableDefinition<[u8; 32], &[u8]> = TableDefinition::new("e");
pub enum ResourceStore {
Redb(Database),
+ Filesystem(PathBuf),
Memory(Mutex<HashMap<Resource, Vec<u8>>>),
}
impl ResourceStore {
- pub fn new_persistent(path: &Path) -> Result<Self> {
+ pub fn new_env() -> Result<Self> {
+ if var("WEARECHAT_RES_CACHE_USE_REDB").is_ok() {
+ ResourceStore::new_redb(
+ &xdg::BaseDirectories::with_prefix("wearechat")?
+ .place_cache_file("resources.db")?,
+ )
+ } else {
+ ResourceStore::new_filesystem(
+ &xdg::BaseDirectories::with_prefix("wearechat")?
+ .create_cache_directory("resources")?,
+ )
+ }
+ }
+ pub fn new_filesystem(path: &Path) -> Result<Self> {
+ info!("using filesystem resource cache in {path:?}");
+ create_dir_all(path)?;
+ Ok(Self::Filesystem(path.to_owned()))
+ }
+ pub fn new_redb(path: &Path) -> Result<Self> {
+ info!("initializing redb resource cache...");
let db = Database::create(path)?;
let txn = db.begin_write()?;
txn.open_table(T_ENTRIES)?;
txn.commit()?;
+ info!("done");
Ok(Self::Redb(db))
}
pub fn new_memory() -> Self {
@@ -55,6 +85,16 @@ impl ResourceStore {
}
}
ResourceStore::Memory(map) => Ok(map.lock().unwrap().get(&key).map(|x| x.to_vec())),
+ ResourceStore::Filesystem(root) => {
+ let path = fs_cache_path(&root, key);
+ if path.exists() {
+ let mut buf = Vec::new();
+ File::open(path)?.read_to_end(&mut buf)?;
+ Ok(Some(buf))
+ } else {
+ Ok(None)
+ }
+ }
}
}
pub fn set_raw(&self, value: &[u8]) -> Result<Resource> {
@@ -70,12 +110,19 @@ impl ResourceStore {
ResourceStore::Memory(map) => {
map.lock().unwrap().insert(key, value.to_vec());
}
+ ResourceStore::Filesystem(root) => {
+ let path = fs_cache_path(&root, key);
+ let path_temp = path.with_extension("part");
+ File::create(&path_temp)?.write_all(value)?;
+ rename(path_temp, path)?;
+ }
}
Ok(key)
}
pub fn iter(&self, mut cb: impl FnMut(&[u8])) -> Result<()> {
match self {
ResourceStore::Redb(_database) => todo!(),
+ ResourceStore::Filesystem(_root) => todo!(),
ResourceStore::Memory(mutex) => {
mutex.lock().unwrap().values().for_each(|v| cb(v));
Ok(())
@@ -89,3 +136,13 @@ pub fn resource_hash(x: &[u8]) -> [u8; 32] {
hasher.update(x);
hasher.finalize().into()
}
+
+fn fs_cache_path(path: &Path, res: Resource) -> PathBuf {
+ path.join(format!(
+ "{:08x}{:08x}{:08x}{:08x}",
+ u64::from_be_bytes(res.0[0..8].try_into().unwrap()),
+ u64::from_be_bytes(res.0[8..16].try_into().unwrap()),
+ u64::from_be_bytes(res.0[16..24].try_into().unwrap()),
+ u64::from_be_bytes(res.0[24..32].try_into().unwrap()),
+ ))
+}