mirror of
				https://github.com/lov3b/ecb-rates.git
				synced 2025-11-04 07:10:18 +01:00 
			
		
		
		
	Fix cache bug
Fix bug where a potentially incorrect resolution would be assumed.
This commit is contained in:
		
							
								
								
									
										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;
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								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,10 +66,14 @@ 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() {
 | 
				
			||||||
 | 
					                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);
 | 
					                    eprintln!("Failed to save to cache with: {:?}", e);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        parsed
 | 
					        parsed
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user