forked from realaravinth/libmedium
cache gists
This commit is contained in:
parent
ed091b5cf2
commit
67a59fe38b
1 changed files with 123 additions and 13 deletions
130
src/data.rs
130
src/data.rs
|
@ -18,19 +18,23 @@ use std::path::Path;
|
|||
|
||||
use actix_web::web;
|
||||
use graphql_client::{reqwest::post_graphql, GraphQLQuery};
|
||||
use reqwest::header::USER_AGENT;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sled::{Db, Tree};
|
||||
|
||||
use crate::proxy::StringUtils;
|
||||
use crate::SETTINGS;
|
||||
|
||||
const CACHE_VERSION: usize = 1;
|
||||
const POST_CACHE_VERSION: usize = 1;
|
||||
const GIST_CACHE_VERSION: usize = 1;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Data {
|
||||
pub client: Client,
|
||||
cache: Db,
|
||||
pub posts: Tree,
|
||||
pub gists: Tree,
|
||||
}
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
|
@ -45,15 +49,51 @@ pub type PostResp = get_post::GetPostPost;
|
|||
|
||||
pub type AppData = web::Data<Data>;
|
||||
|
||||
impl PostResp {
|
||||
pub fn get_gist_id<'a>(&self, url: &'a str) -> &'a str {
|
||||
url.split('/').last().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct GistContent {
|
||||
pub files: Vec<GistFile>,
|
||||
pub html_url: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct GistFile {
|
||||
pub file_name: String,
|
||||
pub content: String,
|
||||
pub language: String,
|
||||
pub raw_url: String,
|
||||
}
|
||||
|
||||
impl GistFile {
|
||||
pub fn get_html_content(&self) -> String {
|
||||
let mut content = self.content.as_str();
|
||||
if self.content.starts_with('"') {
|
||||
content = self.content.slice(1..);
|
||||
}
|
||||
|
||||
if content.ends_with('"') {
|
||||
content = content.slice(..content.len() - 1);
|
||||
}
|
||||
content.replace("\\t", " ")
|
||||
}
|
||||
}
|
||||
|
||||
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 gists = cache.open_tree("gists").unwrap();
|
||||
let res = Self {
|
||||
client: Client::new(),
|
||||
cache,
|
||||
posts,
|
||||
gists,
|
||||
};
|
||||
res.migrate();
|
||||
|
||||
|
@ -61,21 +101,33 @@ impl Data {
|
|||
}
|
||||
|
||||
fn migrate(&self) {
|
||||
const KEY: &str = "POST_CACHE_VERSION";
|
||||
let mut clean = true;
|
||||
if let Ok(Some(v)) = self.posts.get(KEY) {
|
||||
const POST_KEY: &str = "POST_CACHE_VERSION";
|
||||
const GIST_KEY: &str = "GIST_CACHE_VERSION";
|
||||
let trees = [
|
||||
(&self.posts, POST_KEY, POST_CACHE_VERSION),
|
||||
(&self.gists, GIST_KEY, GIST_CACHE_VERSION),
|
||||
];
|
||||
|
||||
for (tree, key, current_version) in trees {
|
||||
if let Ok(Some(v)) = tree.get(key) {
|
||||
let version = bincode::deserialize::<usize>(&v[..]).unwrap();
|
||||
clean = !(version == CACHE_VERSION);
|
||||
}
|
||||
let clean = !(version == current_version);
|
||||
|
||||
if clean {
|
||||
self.posts.clear().unwrap();
|
||||
self.posts.flush().unwrap();
|
||||
self.posts
|
||||
.insert(KEY, bincode::serialize(&CACHE_VERSION).unwrap())
|
||||
log::info!(
|
||||
"Upgrading {} from version {} to version {}",
|
||||
key,
|
||||
version,
|
||||
current_version
|
||||
);
|
||||
tree.clear().unwrap();
|
||||
tree.flush().unwrap();
|
||||
tree.insert(key, bincode::serialize(¤t_version).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_post(&self, id: &str) -> PostResp {
|
||||
match self.posts.get(id) {
|
||||
|
@ -95,4 +147,62 @@ impl Data {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_gist(&self, id: String) -> (String, GistContent) {
|
||||
match self.gists.get(&id) {
|
||||
Ok(Some(v)) => (id, bincode::deserialize(&v[..]).unwrap()),
|
||||
_ => {
|
||||
const URL: &str = "https://api.github.com/gists/";
|
||||
|
||||
let url = format!("{}{}", URL, id);
|
||||
|
||||
let resp = self
|
||||
.client
|
||||
.get(&url)
|
||||
.header(USER_AGENT, "libmedium")
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<serde_json::Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
let files = resp.get("files").unwrap();
|
||||
let v = files.as_object().unwrap();
|
||||
let mut files = Vec::with_capacity(v.len());
|
||||
v.iter().for_each(|(name, file_obj)| {
|
||||
let file = GistFile {
|
||||
file_name: name.to_string(),
|
||||
content: file_obj
|
||||
.get("content")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
language: file_obj
|
||||
.get("language")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
raw_url: file_obj
|
||||
.get("raw_url")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
};
|
||||
files.push(file);
|
||||
});
|
||||
let gist = GistContent {
|
||||
files,
|
||||
html_url: resp.get("html_url").unwrap().to_string(),
|
||||
};
|
||||
|
||||
self.gists
|
||||
.insert(&id, bincode::serialize(&gist).unwrap())
|
||||
.unwrap();
|
||||
(id, gist)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue