mirror of
https://github.com/lov3b/ecb-rates.git
synced 2025-02-22 18:00:11 +01:00
Fix cache bug
Fix bug where a potentially incorrect resolution would be assumed.
This commit is contained in:
parent
81ec482918
commit
96aabc8019
45
src/cache.rs → src/cache/cache.rs
vendored
45
src/cache.rs → src/cache/cache.rs
vendored
@ -3,22 +3,20 @@ use std::io::{BufReader, BufWriter};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use chrono::serde::ts_seconds;
|
|
||||||
use chrono::{DateTime, Local, Utc};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::models::ExchangeRateResult;
|
use crate::cli::Resolution;
|
||||||
use crate::os::Os;
|
use crate::os::Os;
|
||||||
|
|
||||||
|
use super::CacheLine;
|
||||||
|
|
||||||
const FILE_NAME: &'static str = "cache.json";
|
const FILE_NAME: &'static str = "cache.json";
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Cache {
|
pub struct Cache {
|
||||||
#[serde(with = "ts_seconds")]
|
day: Option<CacheLine>,
|
||||||
date: DateTime<Utc>,
|
hist_90: Option<CacheLine>,
|
||||||
|
hist_day: Option<CacheLine>,
|
||||||
#[serde(rename = "camelCase")]
|
|
||||||
pub exchange_rate_results: Vec<ExchangeRateResult>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cache {
|
impl Cache {
|
||||||
@ -37,7 +35,11 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
config_path.push(FILE_NAME);
|
config_path.push(FILE_NAME);
|
||||||
if !config_path.try_exists().unwrap_or_default() {
|
if !config_path.try_exists().unwrap_or_default() {
|
||||||
return None;
|
return Some(Self {
|
||||||
|
day: None,
|
||||||
|
hist_90: None,
|
||||||
|
hist_day: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
match Self::read_config(&config_path) {
|
match Self::read_config(&config_path) {
|
||||||
@ -49,11 +51,20 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(exchange_rate_results: Vec<ExchangeRateResult>) -> Self {
|
pub fn get_cache_line(&self, resolution: Resolution) -> Option<&CacheLine> {
|
||||||
let date = Local::now().to_utc();
|
match resolution {
|
||||||
Self {
|
Resolution::TODAY => self.day.as_ref(),
|
||||||
exchange_rate_results,
|
Resolution::HistDays90 => self.hist_90.as_ref(),
|
||||||
date,
|
Resolution::HistDay => self.hist_day.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cache_line(&mut self, resolution: Resolution, cache_line: CacheLine) {
|
||||||
|
let cache_line_opt = Some(cache_line);
|
||||||
|
match resolution {
|
||||||
|
Resolution::TODAY => self.day = cache_line_opt,
|
||||||
|
Resolution::HistDays90 => self.hist_90 = cache_line_opt,
|
||||||
|
Resolution::HistDay => self.hist_day = cache_line_opt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,12 +88,6 @@ impl Cache {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(&self) -> bool {
|
|
||||||
let today = Local::now().naive_local().date();
|
|
||||||
let saved = self.date.naive_local().date();
|
|
||||||
saved == today
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_config(path: &Path) -> anyhow::Result<Self> {
|
fn read_config(path: &Path) -> anyhow::Result<Self> {
|
||||||
let file = fs::File::open(path)?;
|
let file = fs::File::open(path)?;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
30
src/cache/cache_line.rs
vendored
Normal file
30
src/cache/cache_line.rs
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use chrono::serde::ts_seconds;
|
||||||
|
use chrono::{DateTime, Local, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::models::ExchangeRateResult;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct CacheLine {
|
||||||
|
#[serde(with = "ts_seconds")]
|
||||||
|
date: DateTime<Utc>,
|
||||||
|
|
||||||
|
#[serde(rename = "camelCase")]
|
||||||
|
pub exchange_rate_results: Vec<ExchangeRateResult>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheLine {
|
||||||
|
pub fn validate(&self) -> bool {
|
||||||
|
let today = Local::now().naive_local().date();
|
||||||
|
let saved = self.date.naive_local().date();
|
||||||
|
saved == today
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(exchange_rate_results: Vec<ExchangeRateResult>) -> Self {
|
||||||
|
let date = Local::now().to_utc();
|
||||||
|
Self {
|
||||||
|
exchange_rate_results,
|
||||||
|
date,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
src/cache/mod.rs
vendored
Normal file
5
src/cache/mod.rs
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod cache;
|
||||||
|
mod cache_line;
|
||||||
|
|
||||||
|
pub use cache::Cache;
|
||||||
|
pub use cache_line::CacheLine;
|
31
src/main.rs
31
src/main.rs
@ -1,12 +1,12 @@
|
|||||||
use clap::Parser as _;
|
use clap::Parser as _;
|
||||||
use ecb_rates::cache::Cache;
|
use ecb_rates::cache::{Cache, CacheLine};
|
||||||
use reqwest::{Client, IntoUrl};
|
use reqwest::{Client, IntoUrl};
|
||||||
use std::{borrow::BorrowMut, collections::HashMap, process::ExitCode};
|
use std::{borrow::BorrowMut, collections::HashMap, process::ExitCode};
|
||||||
|
|
||||||
use ecb_rates::cli::{Cli, FormatOption};
|
use ecb_rates::cli::{Cli, FormatOption};
|
||||||
use ecb_rates::models::ExchangeRateResult;
|
use ecb_rates::models::ExchangeRateResult;
|
||||||
use ecb_rates::parsing::parse;
|
use ecb_rates::parsing::parse;
|
||||||
use ecb_rates::table::{TableRef, TableTrait};
|
use ecb_rates::table::{TableRef, TableTrait as _};
|
||||||
|
|
||||||
async fn get_and_parse(url: impl IntoUrl) -> anyhow::Result<Vec<ExchangeRateResult>> {
|
async fn get_and_parse(url: impl IntoUrl) -> anyhow::Result<Vec<ExchangeRateResult>> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
@ -40,10 +40,23 @@ async fn main() -> ExitCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let use_cache = !cli.no_cache;
|
let use_cache = !cli.no_cache;
|
||||||
let cache = if use_cache { Cache::load() } else { None };
|
let mut cache = if use_cache { Cache::load() } else { None };
|
||||||
let cache_ok = cache.as_ref().map_or_else(|| false, |c| c.validate());
|
let cache_ok = cache.as_ref().map_or_else(
|
||||||
|
|| false,
|
||||||
|
|c| {
|
||||||
|
c.get_cache_line(cli.resolution)
|
||||||
|
.map_or_else(|| false, |cl| cl.validate())
|
||||||
|
},
|
||||||
|
);
|
||||||
let mut parsed = if cache_ok {
|
let mut parsed = if cache_ok {
|
||||||
cache.as_ref().unwrap().exchange_rate_results.clone()
|
// These are safe unwraps
|
||||||
|
cache
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.get_cache_line(cli.resolution)
|
||||||
|
.unwrap()
|
||||||
|
.exchange_rate_results
|
||||||
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
let parsed = match get_and_parse(cli.resolution.to_ecb_url()).await {
|
let parsed = match get_and_parse(cli.resolution.to_ecb_url()).await {
|
||||||
Ok(k) => k,
|
Ok(k) => k,
|
||||||
@ -53,8 +66,12 @@ async fn main() -> ExitCode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !cache_ok {
|
if !cache_ok {
|
||||||
if let Err(e) = Cache::new(parsed.clone()).save() {
|
if let Some(cache_safe) = cache.as_mut() {
|
||||||
eprintln!("Failed to save to cache with: {:?}", e);
|
let cache_line = CacheLine::new(parsed.clone());
|
||||||
|
cache_safe.set_cache_line(cli.resolution, cache_line);
|
||||||
|
if let Err(e) = cache_safe.save() {
|
||||||
|
eprintln!("Failed to save to cache with: {:?}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parsed
|
parsed
|
||||||
|
Loading…
x
Reference in New Issue
Block a user