summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/Cargo.toml1
-rw-r--r--shared/src/store.rs61
2 files changed, 60 insertions, 2 deletions
diff --git a/shared/Cargo.toml b/shared/Cargo.toml
index 394983a..b8b431a 100644
--- a/shared/Cargo.toml
+++ b/shared/Cargo.toml
@@ -11,3 +11,4 @@ redb = "2.4.0"
log = "0.4.22"
rand = "0.9.0-beta.1"
blake3 = "1.5.5"
+xdg = "2.5.2"
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()),
+ ))
+}