use anyhow::Result; use redb::{Database, TableDefinition}; use std::{ fs::{File, create_dir_all}, io::{Read, Write}, path::{Path, PathBuf}, }; pub enum Cache { Directory(PathBuf), Redb(Database), } const T_DOWNLOAD: TableDefinition<&str, &[u8]> = TableDefinition::new("dl"); impl Cache { pub fn new_directory() -> Result { let cachedir = xdg::BaseDirectories::with_prefix("weareearth") .unwrap() .create_cache_directory("download") .unwrap(); create_dir_all(cachedir.join("BulkMetadata"))?; create_dir_all(cachedir.join("NodeData"))?; Ok(Self::Directory(cachedir)) } pub fn new_db(path: &Path) -> Result { let db = Database::open(path)?; { let txn = db.begin_write()?; txn.open_table(T_DOWNLOAD)?; txn.commit()?; } Ok(Self::Redb(db)) } pub fn get(&self, path: &str) -> Result>> { match self { Cache::Directory(cachedir) => { let cachepath = cachedir.join(path); if cachepath.exists() { let mut buf = Vec::new(); File::open(cachepath)?.read_to_end(&mut buf)?; Ok(Some(buf.into())) } else { Ok(None) } } Cache::Redb(database) => { let txn = database.begin_read()?; let table = txn.open_table(T_DOWNLOAD)?; let res = table.get(path)?; if let Some(res) = res { Ok(Some(res.value().to_vec())) } else { Ok(None) } } } } pub fn insert(&self, path: &str, data: &[u8]) -> Result<()> { match self { Cache::Directory(cachedir) => { let cachepath = cachedir.join(path); File::create(cachepath)?.write_all(data)?; Ok(()) } Cache::Redb(database) => { let txn = database.begin_write()?; let mut table = txn.open_table(T_DOWNLOAD)?; table.insert(path, data)?; drop(table); txn.commit()?; Ok(()) } } } }