use std::{collections::HashMap, time::Instant}; use actix_web::HttpRequest; use serde::{Deserialize, Serialize}; pub struct Coordinates { pub lat: f32, pub lon: f32, } #[derive(Serialize, Deserialize)] pub struct WeatherDTO { pub sunrise_utc_ms: Option, pub sunset_utc_ms: Option, pub timezone_shift_ms: Option, pub temperature: Option, pub feels_like: Option, pub wind_speed: Option, pub wind_dir: Option, pub gust_speed: Option, pub humidity: Option, pub rain_rate: Option, pub snow_rate: Option, pub cloudiness: Option, pub conditions: Vec, } #[derive(Serialize, Deserialize)] pub struct ForecastDTO { pub list: Vec, } #[derive(Serialize, Deserialize)] pub struct ForecastDatapointDTO { pub timestamp_utc_ms: u64, pub is_day: bool, pub temperature: Option, pub feels_like: Option, pub wind_speed: Option, pub gust_speed: Option, pub wind_dir: Option, pub humidity: Option, pub precipitation_chance: Option, pub rain_rate: Option, pub snow_rate: Option, pub cloudiness: Option, pub conditions: Vec, } #[derive(Debug)] pub struct CacheData { pub data: T, pub created_at: Instant, pub time_to_live_ms: u128, } impl CacheData { pub fn is_valid(&self) -> bool { Instant::now().duration_since(self.created_at).as_millis() < self.time_to_live_ms } pub fn new(data: T) -> Self { Self { data, created_at: Instant::now(), time_to_live_ms: 10_000, } } } #[derive(Default, Debug)] pub struct WebCache { map: HashMap>, } impl WebCache { pub async fn try_cached_request( &mut self, key: &HttpRequest, fun: F, ) -> Result where F: AsyncFnOnce() -> Result, { self.try_cached_uri(key.uri().path().to_string(), fun).await } pub async fn try_cached_uri(&mut self, key: String, fun: F) -> Result where F: AsyncFnOnce() -> Result, { if let Some(cached) = self.map.get(&key) { if cached.is_valid() { return Ok(cached.data.clone()); } } self.map.remove(&key); let data = fun().await?; self.map.insert(key.clone(), CacheData::new(data.clone())); Ok(data) } }