implemented cache

This commit is contained in:
ThetaDev 2022-07-31 20:13:18 +02:00
parent d7caceba7a
commit db6ece6c61
6 changed files with 261 additions and 158 deletions

View file

@ -1,17 +1,25 @@
use std::{future::Future, sync::Arc};
use std::{
fs::File,
future::Future,
io::BufReader,
path::{Path, PathBuf},
sync::Arc,
};
use anyhow::Result;
use chrono::{DateTime, Duration, Utc};
use log::{error, info};
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Cache {
file: Option<PathBuf>,
data: Arc<Mutex<CacheData>>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct CacheData {
struct CacheData {
desktop_client: Option<CacheEntry<DesktopClientData>>,
deobf: Option<CacheEntry<DeobfData>>,
}
@ -38,10 +46,10 @@ pub struct DesktopClientData {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct DeobfData {
js_url: String,
sig_fn: String,
nsig_fn: String,
sts: String,
pub js_url: String,
pub sig_fn: String,
pub nsig_fn: String,
pub sts: String,
}
impl Cache {
@ -52,10 +60,11 @@ impl Cache {
let mut cache = self.data.lock().await;
if cache.desktop_client.is_none()
|| cache.desktop_client.as_ref().unwrap().last_update < Utc::now() - Duration::days(1)
|| cache.desktop_client.as_ref().unwrap().last_update < Utc::now() - Duration::hours(24)
{
let cdata = updater.await?;
cache.desktop_client = Some(CacheEntry::from(cdata.clone()));
self.save(&cache);
Ok(cdata)
} else {
Ok(cache.desktop_client.as_ref().unwrap().data.clone())
@ -68,33 +77,102 @@ impl Cache {
{
let mut cache = self.data.lock().await;
if cache.deobf.is_none()
|| cache.deobf.as_ref().unwrap().last_update < Utc::now() - Duration::days(1)
|| cache.deobf.as_ref().unwrap().last_update < Utc::now() - Duration::hours(1)
{
let deobf_data = updater.await?;
cache.deobf = Some(CacheEntry::from(deobf_data.clone()));
self.save(&cache);
Ok(deobf_data)
} else {
Ok(cache.deobf.as_ref().unwrap().data.clone())
}
}
pub async fn to_json(&self) -> Result<String, serde_json::Error> {
pub async fn to_json(&self) -> Result<String> {
let cache = self.data.lock().await;
serde_json::to_string(&cache.clone())
Ok(serde_json::to_string(&cache.clone())?)
}
pub async fn from_json(&self, json: &str) -> Result<(), serde_json::Error> {
let cd = serde_json::from_str::<CacheData>(json)?;
pub async fn to_json_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let cache = self.data.lock().await;
Ok(serde_json::to_writer(&File::create(path)?, &cache.clone())?)
}
let mut cache = self.data.lock().await;
*cache = cd;
pub fn from_json(json: &str) -> Self {
let data: CacheData = match serde_json::from_str(json) {
Ok(cd) => cd,
Err(e) => {
error!(
"Could not load cache from json, falling back to default. Error: {}",
e
);
CacheData::default()
}
};
Cache {
data: Arc::new(Mutex::new(data)),
file: None,
}
}
Ok(())
pub fn from_json_file<P: AsRef<Path>>(path: P) -> Self {
let file = match File::open(path.as_ref()) {
Ok(file) => file,
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
info!(
"Cache json file at {} not found, will be created",
path.as_ref().to_string_lossy()
)
} else {
error!(
"Could not open cache json file, falling back to default. Error: {}",
e
);
}
return Cache {
file: Some(path.as_ref().to_path_buf()),
..Default::default()
};
}
};
let data: CacheData = match serde_json::from_reader(BufReader::new(file)) {
Ok(data) => data,
Err(e) => {
error!(
"Could not load cache from json, falling back to default. Error: {}",
e
);
return Cache {
file: Some(path.as_ref().to_path_buf()),
..Default::default()
};
}
};
Cache {
data: Arc::new(Mutex::new(data)),
file: Some(path.as_ref().to_path_buf()),
}
}
fn save(&self, cache: &CacheData) {
match self.file.as_ref() {
Some(file) => match File::create(file) {
Ok(file) => match serde_json::to_writer(file, cache) {
Ok(_) => {}
Err(e) => error!("Could not write cache to json. Error: {}", e),
},
Err(e) => error!("Could not open cache json file. Error: {}", e),
},
None => {}
}
}
}
#[cfg(test)]
mod tests {
use temp_testdir::TempDir;
use super::*;
#[tokio::test]
@ -143,9 +221,69 @@ mod tests {
);
let json = cache.to_json().await.unwrap();
let new_cache = Cache::from_json(&json);
let new_cache = Cache::default();
new_cache.from_json(&json).await.unwrap();
assert_eq!(
new_cache
.get_desktop_client_data(async {
Ok(DesktopClientData {
client_version: "".to_owned(),
})
})
.await
.unwrap(),
cdata
);
assert_eq!(
new_cache
.get_deobf_data(async {
Ok(DeobfData {
js_url: "".to_owned(),
nsig_fn: "".to_owned(),
sig_fn: "".to_owned(),
sts: "".to_owned(),
})
})
.await
.unwrap(),
deobf_data
);
}
#[tokio::test]
async fn test_file() {
let temp = TempDir::default();
let mut file_path = PathBuf::from(temp.as_ref());
file_path.push("cache.json");
let cache = Cache::from_json_file(file_path.clone());
let cdata = cache
.get_desktop_client_data(async {
Ok(DesktopClientData {
client_version: "1.2.3".to_owned(),
})
})
.await
.unwrap();
let deobf_data = cache
.get_deobf_data(async {
Ok(DeobfData {
js_url:
"https://www.youtube.com/s/player/011af516/player_ias.vflset/en_US/base.js"
.to_owned(),
sig_fn: "t_sig_fn".to_owned(),
nsig_fn: "t_nsig_fn".to_owned(),
sts: "t_sts".to_owned(),
})
})
.await
.unwrap();
assert!(file_path.exists());
let new_cache = Cache::from_json_file(file_path.clone());
assert_eq!(
new_cache