Skip to content

Commit 60c0a78

Browse files
committed
backend: remove lifetimes and add different stores
1 parent 367987a commit 60c0a78

File tree

15 files changed

+480
-298
lines changed

15 files changed

+480
-298
lines changed

src/cache/firestore.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use crate::parse::Locations;
2+
use async_compression::tokio::bufread;
3+
use chrono::{DateTime, Utc};
4+
use firestore::FirestoreDb;
5+
use log::info;
6+
use tokio::io::AsyncReadExt;
7+
8+
use super::MenuCache;
9+
10+
const CACHES_COLLECTION: &str = "caches";
11+
12+
#[derive(Debug)]
13+
pub struct Firestore {
14+
db: FirestoreDb,
15+
// data: String,
16+
}
17+
18+
impl Firestore {
19+
pub async fn open() -> crate::Result<Self> {
20+
let db = FirestoreDb::new("ucsc-menu").await?;
21+
Ok(Self {
22+
db,
23+
// data: String::new(),
24+
})
25+
}
26+
27+
pub async fn load(&mut self) -> crate::Result<Option<MenuCache>> {
28+
if let Some(cache) = self
29+
.db
30+
.fluent()
31+
.select()
32+
.by_id_in(CACHES_COLLECTION)
33+
.obj::<GCloudMenuCache>()
34+
.one("menu")
35+
.await?
36+
{
37+
Ok(Some(cache.decompress().await))
38+
} else {
39+
Ok(None)
40+
}
41+
// Ok(cache.decompress(&mut self.data).await)
42+
}
43+
44+
pub async fn save(&self, cache: &MenuCache) -> crate::Result<()> {
45+
let compressed = GCloudMenuCache::compress(cache).await;
46+
self.db
47+
.fluent()
48+
.update()
49+
.in_col(CACHES_COLLECTION)
50+
.document_id("menu")
51+
.object(&compressed)
52+
// need to specify type because of dependency_on_unit_never_type_fallback
53+
.execute::<()>()
54+
.await?;
55+
Ok(())
56+
}
57+
}
58+
59+
#[derive(serde::Serialize, serde::Deserialize, Default)]
60+
struct GCloudMenuCache {
61+
cached_at: DateTime<Utc>,
62+
data: Vec<u8>,
63+
}
64+
65+
impl GCloudMenuCache {
66+
async fn decompress<'a>(self /* dst: &mut String */) -> MenuCache {
67+
if self.data.is_empty() {
68+
return MenuCache {
69+
cached_at: self.cached_at,
70+
locations: Locations::default(),
71+
};
72+
}
73+
let mut decompress = bufread::GzipDecoder::new(self.data.as_slice());
74+
info!("Size of data compressed: {}", self.data.len());
75+
let mut dst = String::new();
76+
dst.reserve(self.data.len() * 8);
77+
let _len = decompress
78+
.read_to_string(&mut dst)
79+
.await
80+
.expect("should succeed");
81+
info!("Size of data uncompressed: {}", dst.len());
82+
let locations: Locations =
83+
serde_json::from_str(&*dst).expect("Data parse should always be valid");
84+
MenuCache {
85+
cached_at: self.cached_at,
86+
locations,
87+
}
88+
}
89+
90+
// TODO: better name
91+
async fn compress(data: &MenuCache) -> Self {
92+
let json = serde_json::to_string(data.locations()).unwrap();
93+
let mut compressed = Vec::with_capacity(json.len() / 4);
94+
let mut compress = bufread::GzipEncoder::new(std::io::Cursor::new(json));
95+
compress
96+
.read_buf(&mut compressed)
97+
.await
98+
.expect("This should succeed");
99+
Self {
100+
cached_at: data.cached_at,
101+
data: compressed,
102+
}
103+
}
104+
}
105+
106+
#[cfg(test)]
107+
mod tests {
108+
109+
use std::time::Instant;
110+
111+
use super::*;
112+
113+
#[tokio::test]
114+
async fn test_open() {
115+
pretty_env_logger::init();
116+
let mut db = Firestore::open().await.unwrap();
117+
let _mc = db.load().await.unwrap();
118+
}
119+
120+
#[tokio::test]
121+
async fn test_refresh() {
122+
let mut db = Firestore::open().await.unwrap();
123+
let mut mc = db.load().await.unwrap();
124+
let start = Instant::now();
125+
todo!();
126+
println!("{:?}", start.elapsed());
127+
}
128+
}

src/cache/local.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use std::path::{Path, PathBuf};
2+
use tokio::fs;
3+
4+
use super::MenuCache;
5+
6+
#[derive(Debug)]
7+
pub struct FileStore(PathBuf);
8+
9+
impl FileStore {
10+
pub async fn open(p: impl AsRef<Path>) -> crate::Result<Self> {
11+
let p = p.as_ref();
12+
// fs::File::options()
13+
// .create(true)
14+
// .write(true)
15+
// .read(true)
16+
// .open(p)
17+
// .await?;
18+
19+
Ok(Self(p.to_owned()))
20+
}
21+
22+
pub async fn load(&self) -> crate::Result<Option<MenuCache>> {
23+
if fs::try_exists(&self.0).await? {
24+
let f = fs::File::open(&self.0).await?;
25+
let mut f = f.into_std().await;
26+
serde_json::from_reader(&mut f).map_err(From::from)
27+
} else {
28+
Ok(None)
29+
}
30+
}
31+
32+
pub async fn save(&self, value: &MenuCache) -> crate::Result<()> {
33+
let f = fs::File::options()
34+
.create(true)
35+
.write(true)
36+
.open(&self.0)
37+
.await?;
38+
// TODO
39+
let mut f = f.into_std().await;
40+
serde_json::to_writer_pretty(&mut f, value).map_err(From::from)
41+
}
42+
}

src/cache/menu_cache.rs

Lines changed: 0 additions & 185 deletions
This file was deleted.

0 commit comments

Comments
 (0)