feat: caching
This commit is contained in:
36
src/dwd.rs
36
src/dwd.rs
@@ -1,10 +1,15 @@
|
|||||||
use std::collections::{BTreeMap, HashMap};
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DwdCache {}
|
pub struct DwdCache {
|
||||||
|
dwd_responses: HashMap<Vec<String>, (Instant, Result<Forecast, String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
pub type Forecast = HashMap<String, ForecastDatas>;
|
pub type Forecast = HashMap<String, ForecastDatas>;
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -168,7 +173,32 @@ impl ForecastData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn forecast(ids: &[&str], cache: &mut DwdCache) -> Result<Forecast, String> {
|
pub async fn forecast<'a>(
|
||||||
|
ids: Vec<String>,
|
||||||
|
cache: &'a mut DwdCache,
|
||||||
|
) -> Result<&'a Forecast, &'a String> {
|
||||||
|
let now = Instant::now();
|
||||||
|
cache.dwd_responses.retain(|_, (time, cached)| {
|
||||||
|
now.saturating_duration_since(*time).as_secs() < if cached.is_ok() { 600 } else { 90 }
|
||||||
|
});
|
||||||
|
let v = if cache.dwd_responses.contains_key(&ids) {
|
||||||
|
// cache is fresh, don't remove it,
|
||||||
|
// don't fetch new data, or_insert_with will not run.
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// there is no cache (never was or it was outdated).
|
||||||
|
// fetch new data since or_insert_with will run.
|
||||||
|
Some(forecast_impl(&ids).await)
|
||||||
|
};
|
||||||
|
cache
|
||||||
|
.dwd_responses
|
||||||
|
.entry(ids)
|
||||||
|
// closure will run exactly when `v` is `Some`
|
||||||
|
.or_insert_with(|| (now, v.unwrap()))
|
||||||
|
.1
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
|
async fn forecast_impl(ids: &[String]) -> Result<Forecast, String> {
|
||||||
dbg!(ids);
|
dbg!(ids);
|
||||||
let mut url =
|
let mut url =
|
||||||
Url::parse("https://app-prod-ws.warnwetter.de/v30/stationOverviewExtended").unwrap();
|
Url::parse("https://app-prod-ws.warnwetter.de/v30/stationOverviewExtended").unwrap();
|
||||||
|
|||||||
@@ -196,13 +196,13 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page {
|
|||||||
let q = q.to_lowercase();
|
let q = q.to_lowercase();
|
||||||
dwd_stations
|
dwd_stations
|
||||||
.range((q.clone(), 0)..=(q, usize::MAX))
|
.range((q.clone(), 0)..=(q, usize::MAX))
|
||||||
.map(|(_, station)| station.station.as_str())
|
.map(|(_, station)| station.station.clone())
|
||||||
.take(WEATHER_MAX_STATIONS)
|
.take(WEATHER_MAX_STATIONS)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
LocationString::Station(q) => q
|
LocationString::Station(q) => q
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.as_str())
|
.map(|s| s.clone())
|
||||||
.take(WEATHER_MAX_STATIONS)
|
.take(WEATHER_MAX_STATIONS)
|
||||||
.collect(),
|
.collect(),
|
||||||
LocationString::Coords(lat, lon) => vec![
|
LocationString::Coords(lat, lon) => vec![
|
||||||
@@ -211,7 +211,7 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page {
|
|||||||
.min_by(|a, b| dist2(a, *lat, *lon).total_cmp(&dist2(b, *lat, *lon)))
|
.min_by(|a, b| dist2(a, *lat, *lon).total_cmp(&dist2(b, *lat, *lon)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.station
|
.station
|
||||||
.as_str(),
|
.clone(),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
if stations.is_empty() {
|
if stations.is_empty() {
|
||||||
@@ -220,7 +220,7 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page {
|
|||||||
"could not find any such station".to_owned(),
|
"could not find any such station".to_owned(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
match crate::dwd::forecast(&stations, dwd_cache).await {
|
match crate::dwd::forecast(stations, dwd_cache).await {
|
||||||
Ok(forecast) => {
|
Ok(forecast) => {
|
||||||
fn forecasts(
|
fn forecasts(
|
||||||
forecast: &HashMap<String, ForecastDatas>,
|
forecast: &HashMap<String, ForecastDatas>,
|
||||||
|
|||||||
Reference in New Issue
Block a user