103 lines
2.5 KiB
Rust
103 lines
2.5 KiB
Rust
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<u64>,
|
|
pub sunset_utc_ms: Option<u64>,
|
|
pub timezone_shift_ms: Option<i64>,
|
|
pub temperature: Option<f32>,
|
|
pub feels_like: Option<f32>,
|
|
pub wind_speed: Option<f32>,
|
|
pub wind_dir: Option<f32>,
|
|
pub gust_speed: Option<f32>,
|
|
pub humidity: Option<f32>,
|
|
pub rain_rate: Option<f32>,
|
|
pub snow_rate: Option<f32>,
|
|
pub cloudiness: Option<f32>,
|
|
pub conditions: Vec<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ForecastDTO {
|
|
pub list: Vec<ForecastDatapointDTO>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ForecastDatapointDTO {
|
|
pub timestamp_utc_ms: u64,
|
|
pub is_day: bool,
|
|
pub temperature: Option<f32>,
|
|
pub feels_like: Option<f32>,
|
|
pub wind_speed: Option<f32>,
|
|
pub gust_speed: Option<f32>,
|
|
pub wind_dir: Option<f32>,
|
|
pub humidity: Option<f32>,
|
|
pub precipitation_chance: Option<f32>,
|
|
pub rain_rate: Option<f32>,
|
|
pub snow_rate: Option<f32>,
|
|
pub cloudiness: Option<f32>,
|
|
pub conditions: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct CacheData<T> {
|
|
pub data: T,
|
|
pub created_at: Instant,
|
|
pub time_to_live_ms: u128,
|
|
}
|
|
|
|
impl<T> CacheData<T> {
|
|
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<String, CacheData<String>>,
|
|
}
|
|
|
|
impl WebCache {
|
|
pub async fn try_cached_request<F>(
|
|
&mut self,
|
|
key: &HttpRequest,
|
|
fun: F,
|
|
) -> Result<String, String>
|
|
where
|
|
F: AsyncFnOnce() -> Result<String, String>,
|
|
{
|
|
self.try_cached_uri(key.uri().path().to_string(), fun).await
|
|
}
|
|
|
|
pub async fn try_cached_uri<F>(&mut self, key: String, fun: F) -> Result<String, String>
|
|
where
|
|
F: AsyncFnOnce() -> Result<String, String>,
|
|
{
|
|
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)
|
|
}
|
|
}
|