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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::path::Path;
use actix_web::web;
use graphql_client::{reqwest::post_graphql, GraphQLQuery};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use sled::{Db, Tree};
use crate::SETTINGS;
const CACHE_VERSION: usize = 1;
#[derive(Clone)]
pub struct Data {
pub client: Client,
cache: Db,
pub posts: Tree,
}
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "schemas/schema.graphql",
query_path = "schemas/query.graphql",
response_derives = "Debug, Serialize, Deserialize, Clone"
)]
pub struct GetPost;
pub type PostResp = get_post::GetPostPost;
pub type AppData = web::Data<Data>;
impl Data {
pub fn new() -> AppData {
let path = Path::new(SETTINGS.cache.as_ref().unwrap()).join("posts_cache");
let cache = sled::open(path).unwrap();
let posts = cache.open_tree("posts").unwrap();
let res = Self {
client: Client::new(),
cache,
posts,
};
res.migrate();
AppData::new(res)
}
fn migrate(&self) {
const KEY: &str = "POST_CACHE_VERSION";
let mut clean = true;
if let Ok(Some(v)) = self.posts.get(KEY) {
let version = bincode::deserialize::<usize>(&v[..]).unwrap();
clean = !(version == CACHE_VERSION);
}
if clean {
self.posts.clear().unwrap();
self.posts.flush().unwrap();
self.posts
.insert(KEY, bincode::serialize(&CACHE_VERSION).unwrap())
.unwrap();
}
}
pub async fn get_post(&self, id: &str) -> PostResp {
match self.posts.get(id) {
Ok(Some(v)) => bincode::deserialize(&v[..]).unwrap(),
_ => {
let vars = get_post::Variables { id: id.to_owned() };
const URL: &str = "https://medium.com/_/graphql";
let res = post_graphql::<GetPost, _>(&self.client, URL, vars)
.await
.unwrap();
let res = res.data.expect("missing response data").post.unwrap();
self.posts
.insert(id, bincode::serialize(&res).unwrap())
.unwrap();
res
}
}
}
}