unisuedzeiger/src/cache.rs
2025-03-02 03:27:51 +01:00

129 lines
4.8 KiB
Rust

use std::time::Duration;
use chrono::DateTime;
use tokio::{sync::Mutex, time::Instant};
use crate::api::{bahnhof_get_departures, ApiClient};
pub struct Cache {
pub index: String,
pub nojs: String,
pub data: Mutex<Data>,
pub api_client: Mutex<ApiClient>,
pub api_next_update: Mutex<Instant>,
pub bahnhof_html: Mutex<String>,
pub bahnhof_next_update: Mutex<Instant>,
}
pub struct Data {
pub seq: u8,
pub departures: Vec<Departure>,
// pub changes: [Vec<Change>; 10],
}
#[derive(Debug)]
pub struct Departure {
pub route_name: Option<String>,
pub departure_direction_text: Option<String>,
pub vehicle_number: Option<u32>,
pub departure_time: Option<DateTime<chrono::Local>>,
pub scheduled_time: Option<DateTime<chrono::Local>>,
pub direction: Option<i32>,
}
impl Cache {
pub fn new(index: String, nojs: String, swu_stop_number: Option<u32>) -> Self {
let now = Instant::now();
Self {
index,
nojs,
data: Mutex::new(Data {
seq: 0,
departures: vec![],
}),
api_client: Mutex::new(if let Some(swu_stop_number) = swu_stop_number {
ApiClient::new_custom(swu_stop_number)
} else {
ApiClient::new()
}),
api_next_update: Mutex::new(now),
bahnhof_html: Mutex::new(String::new()),
bahnhof_next_update: Mutex::new(now),
}
}
pub async fn update_swu(&self) -> Duration {
let mut next_update = self.api_next_update.lock().await;
let now = Instant::now();
if now >= *next_update {
let delay = Duration::from_secs(14);
let mut api = self.api_client.lock().await;
match api.api_get().await {
Ok(()) => {
// TODO: find changes
// increment sequence number thingy (ze counting boi)
let mut data = self.data.lock().await;
data.seq += 1;
if data.seq >= 10 {
data.seq = 0;
}
// store departures
let departures = api
.departures
.iter()
.map(|departure| {
let direction = departure
.route_name
.as_ref()
.and_then(|rn| {
departure.departure_direction_text.as_ref().and_then(|dt| {
api.directions
.get(rn)
.and_then(|v| v.get(dt).and_then(|v| v.as_ref()))
})
})
.filter(|(_, _, success)| *success > 2)
.map(|(_, dir, _)| *dir);
Departure {
route_name: departure.route_name.clone(),
departure_direction_text: departure
.departure_direction_text
.clone(),
vehicle_number: departure.vehicle_number,
departure_time: departure
.departure_time_actual
.as_ref()
.or(departure.departure_time_scheduled.as_ref())
.cloned(),
scheduled_time: departure.departure_time_scheduled.clone(),
direction,
}
})
.collect();
data.departures = departures;
}
Err(e) => eprintln!("Couldn't get departures from swu: {e}"),
}
*next_update = Instant::now() + delay;
delay
} else {
*next_update - now
}
}
pub async fn update_bahn(&self) -> Duration {
let mut next_update = self.bahnhof_next_update.lock().await;
let now = Instant::now();
if now >= *next_update {
let delay = Duration::from_secs(59);
// bahnhof api request
match bahnhof_get_departures().await {
Ok(v) => {
*self.bahnhof_html.lock().await = v;
}
Err(e) => eprintln!("Couldn't get departures from bahnhof: {e}"),
}
*next_update = Instant::now() + delay;
delay
} else {
*next_update - now
}
}
}