Merge branch 'faster-cache'

This commit is contained in:
Love 2025-01-09 14:44:58 +01:00
commit a39d0331b3
3 changed files with 40 additions and 52 deletions

61
src/cache/cache.rs vendored
View File

@ -1,26 +1,19 @@
use std::fs; use std::fs;
use std::io::{BufReader, BufWriter}; use std::io::{BufReader, BufWriter};
use std::path::Path; use std::path::{Path, PathBuf};
use anyhow::Context;
use serde::{Deserialize, Serialize};
use super::CacheLine;
use crate::cli::View; use crate::cli::View;
use crate::os::Os; use crate::os::Os;
use super::CacheLine; #[derive(Debug)]
const FILE_NAME: &'static str = "cache.json";
#[derive(Serialize, Deserialize, Debug)]
pub struct Cache { pub struct Cache {
day: Option<CacheLine>, cache_line: Option<CacheLine>,
hist_90: Option<CacheLine>, config_path: PathBuf,
hist_day: Option<CacheLine>,
} }
impl Cache { impl Cache {
pub fn load() -> Option<Self> { pub fn load(view: View) -> Option<Self> {
let config_opt = Os::get_current()?.get_config_path(); let config_opt = Os::get_current()?.get_config_path();
let mut config_path = match config_opt { let mut config_path = match config_opt {
Ok(k) => k, Ok(k) => k,
@ -33,17 +26,19 @@ impl Cache {
eprintln!("Failed to create config dir: {:?}", e); eprintln!("Failed to create config dir: {:?}", e);
return None; return None;
} }
config_path.push(FILE_NAME); config_path.push(format!("{}.json", view.get_name()));
if !config_path.try_exists().unwrap_or_default() { if !config_path.try_exists().unwrap_or_default() {
return Some(Self { return Some(Self {
day: None, cache_line: None,
hist_90: None, config_path,
hist_day: None,
}); });
} }
match Self::read_config(&config_path) { match Self::read_config(&config_path) {
Ok(k) => Some(k), Ok(cache_line) => Some(Self {
cache_line: Some(cache_line),
config_path,
}),
Err(e) => { Err(e) => {
eprintln!("Config path is invalid, or cannot be created: {:?}", e); eprintln!("Config path is invalid, or cannot be created: {:?}", e);
None None
@ -51,44 +46,28 @@ impl Cache {
} }
} }
pub fn get_cache_line(&self, resolution: View) -> Option<&CacheLine> { pub fn get_cache_line(&self) -> Option<&CacheLine> {
match resolution { self.cache_line.as_ref()
View::TODAY => self.day.as_ref(),
View::HistDays90 => self.hist_90.as_ref(),
View::HistDaysAll => self.hist_day.as_ref(),
}
} }
pub fn set_cache_line(&mut self, resolution: View, cache_line: CacheLine) { pub fn set_cache_line(&mut self, cache_line: CacheLine) {
let cache_line_opt = Some(cache_line); self.cache_line = Some(cache_line);
match resolution {
View::TODAY => self.day = cache_line_opt,
View::HistDays90 => self.hist_90 = cache_line_opt,
View::HistDaysAll => self.hist_day = cache_line_opt,
}
} }
pub fn save(&self) -> anyhow::Result<()> { pub fn save(&self) -> anyhow::Result<()> {
let mut config_path = Os::get_current()
.context("Failed to get config home")?
.get_config_path()?;
fs::create_dir_all(&config_path)?;
config_path.push(FILE_NAME);
let file = fs::File::options() let file = fs::File::options()
.write(true) .write(true)
.create(true) .create(true)
.truncate(true) .truncate(true)
.open(&config_path)?; .open(&self.config_path)?;
let writer = BufWriter::new(file); let writer = BufWriter::new(file);
serde_json::to_writer(writer, self)?; serde_json::to_writer(writer, &self.cache_line)?;
Ok(()) Ok(())
} }
fn read_config(path: &Path) -> anyhow::Result<Self> { fn read_config(path: &Path) -> anyhow::Result<CacheLine> {
let file = fs::File::open(path)?; let file = fs::File::open(path)?;
let reader = BufReader::new(file); let reader = BufReader::new(file);
Ok(serde_json::from_reader(reader)?) Ok(serde_json::from_reader(reader)?)

View File

@ -46,8 +46,8 @@ pub struct Cli {
pub max_decimals: u8, pub max_decimals: u8,
/// Amount of data /// Amount of data
#[arg(value_enum, default_value_t = View::TODAY, long="resolution", short='r')] #[arg(value_enum, default_value_t = View::TODAY, long="view", short='v')]
pub resolution: View, pub view: View,
} }
#[derive(Debug, Clone, Copy, ValueEnum)] #[derive(Debug, Clone, Copy, ValueEnum)]
@ -74,6 +74,14 @@ impl View {
View::HistDaysAll => ecb_url::hist::DAYS_ALL, View::HistDaysAll => ecb_url::hist::DAYS_ALL,
} }
} }
pub fn get_name(&self) -> &'static str {
match self {
View::TODAY => "today",
View::HistDays90 => "last-90-days",
View::HistDaysAll => "all-days",
}
}
} }
impl SortBy { impl SortBy {

View File

@ -25,25 +25,26 @@ async fn main() -> ExitCode {
let mut header_description = HeaderDescription::new(); let mut header_description = HeaderDescription::new();
let use_cache = !cli.no_cache; let use_cache = !cli.no_cache;
let mut cache = if use_cache { Cache::load() } else { None }; let mut cache = if use_cache {
Cache::load(cli.view)
} else {
None
};
let cache_ok = cache.as_ref().map_or_else( let cache_ok = cache.as_ref().map_or_else(
|| false, || false,
|c| { |c| c.get_cache_line().map_or_else(|| false, |cl| cl.is_valid()),
c.get_cache_line(cli.resolution)
.map_or_else(|| false, |cl| cl.is_valid())
},
); );
let mut parsed = if cache_ok { let mut parsed = if cache_ok {
// These are safe unwraps // These are safe unwraps
cache cache
.as_ref() .as_ref()
.unwrap() .unwrap()
.get_cache_line(cli.resolution) .get_cache_line()
.unwrap() .unwrap()
.exchange_rate_results .exchange_rate_results
.clone() .clone()
} else { } else {
let parsed = match get_and_parse(cli.resolution.to_ecb_url()).await { let parsed = match get_and_parse(cli.view.to_ecb_url()).await {
Ok(k) => k, Ok(k) => k,
Err(e) => { Err(e) => {
eprintln!("Failed to get/parse data from ECB: {}", e); eprintln!("Failed to get/parse data from ECB: {}", e);
@ -56,7 +57,7 @@ async fn main() -> ExitCode {
|| true, || true,
|cache_local| { |cache_local| {
cache_local cache_local
.get_cache_line(cli.resolution) .get_cache_line()
.map_or_else(|| true, |cache_line| cache_line == &parsed) .map_or_else(|| true, |cache_line| cache_line == &parsed)
}, },
); );
@ -64,7 +65,7 @@ async fn main() -> ExitCode {
if not_equal_cache { if not_equal_cache {
if let Some(cache_safe) = cache.as_mut() { if let Some(cache_safe) = cache.as_mut() {
let cache_line = CacheLine::new(parsed.clone()); let cache_line = CacheLine::new(parsed.clone());
cache_safe.set_cache_line(cli.resolution, cache_line); cache_safe.set_cache_line(cache_line);
if let Err(e) = cache_safe.save() { if let Err(e) = cache_safe.save() {
eprintln!("Failed to save to cache with: {:?}", e); eprintln!("Failed to save to cache with: {:?}", e);
} }