1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
use anyhow::Result;
use redb::{Database, Durability, TableDefinition};
use std::{
fs::create_dir_all,
path::{Path, PathBuf},
};
use tokio::{
fs::File,
io::{AsyncReadExt, AsyncWriteExt},
};
pub enum Cache {
Directory(PathBuf),
Redb(Database),
}
const T_DOWNLOAD: TableDefinition<&str, &[u8]> = TableDefinition::new("dl");
impl Cache {
pub fn new_directory() -> Result<Self> {
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<Self> {
let db = Database::create(path)?;
{
let txn = db.begin_write()?;
txn.open_table(T_DOWNLOAD)?;
txn.commit()?;
}
Ok(Self::Redb(db))
}
pub async fn get(&self, path: &str) -> Result<Option<Vec<u8>>> {
match self {
Cache::Directory(cachedir) => {
let cachepath = cachedir.join(path);
if cachepath.exists() {
let mut buf = Vec::new();
File::open(cachepath).await?.read_to_end(&mut buf).await?;
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 async fn insert(&self, path: &str, data: &[u8]) -> Result<()> {
match self {
Cache::Directory(cachedir) => {
let cachepath = cachedir.join(path);
File::create(cachepath).await?.write_all(data).await?;
Ok(())
}
Cache::Redb(database) => {
let mut txn = database.begin_write()?;
txn.set_durability(Durability::Eventual);
txn.set_quick_repair(true);
let mut table = txn.open_table(T_DOWNLOAD)?;
table.insert(path, data)?;
drop(table);
txn.commit()?;
Ok(())
}
}
}
}
|