kelikatti/kelikatti-api/src/lib.rs

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)
}
}