From 612e394637534a7591f534e5ef4dc951d9702fae Mon Sep 17 00:00:00 2001 From: Jorge Leitao Date: Mon, 22 Jan 2024 07:52:59 +0100 Subject: [PATCH] Simpler test --- src/lib.rs | 4 +- src/trace_month.rs | 113 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/trace_month.rs diff --git a/src/lib.rs b/src/lib.rs index d8747e7..2d82ffc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,8 +122,8 @@ impl Iterator for DateIter { mod test { use super::*; - #[tokio::test] - async fn work() { + #[test] + fn work() { assert_eq!( DateIter { from: time::Date::from_calendar_date(2022, time::Month::January, 1).unwrap(), diff --git a/src/trace_month.rs b/src/trace_month.rs new file mode 100644 index 0000000..b729a10 --- /dev/null +++ b/src/trace_month.rs @@ -0,0 +1,113 @@ +use super::icao_to_trace::*; +use std::{ + collections::{HashMap, HashSet}, + error::Error, +}; + +use futures::{StreamExt, TryStreamExt}; +use time::Date; + +use super::Position; +use crate::{fs, fs_azure, Aircraft}; + +fn cache_file_path(icao: &str, date: &time::Date) -> String { + format!( + "{DIRECTORY}/{DATABASE}/{}-{}/trace_full_{icao}.json", + date.year(), + date.month() as u8 + ) +} + +fn get_month(current: &time::Date) -> (time::Date, time::Date) { + let first_of_month = + time::Date::from_calendar_date(current.year(), current.month(), 1).unwrap(); + + let next_month = current.month().next(); + let first_of_next_month = (next_month == time::Month::January) + .then(|| { + time::Date::from_calendar_date(current.year() + 1, time::Month::January, 1) + .expect("day 1 never errors") + }) + .unwrap_or_else(|| { + time::Date::from_calendar_date(current.year(), next_month, 1) + .expect("day 1 never errors") + }); + (first_of_month, first_of_next_month) +} + +async fn month_positions( + month: &time::Date, + aircraft: &Aircraft, + client: Option<&super::fs_azure::ContainerClient>, +) -> Result>, Box> { + log::info!("month_positions({month},{})", aircraft.icao_number); + assert_eq!(month.day(), 1); + let blob_name = cache_file_path(&aircraft.icao_number, &month); + + let (from, to) = get_month(&month); + let action = fs::CacheAction::from_date(&to); + + // returns positions in the month, cached + let fetch = async { + let positions = aircraft_positions(from, to, aircraft, client) + .await + .unwrap(); + + let positions = positions + .into_iter() + .map(|(d, p)| (d.to_string(), p)) + .collect::>(); + + let mut bytes: Vec = Vec::new(); + serde_json::to_writer(&mut bytes, &positions)?; + Ok(bytes) + }; + + let r = fs_azure::cached_call(&blob_name, fetch, action, client).await?; + Ok(serde_json::from_slice(&r)?) +} + +pub async fn cached_aircraft_positions( + from: Date, + to: Date, + aircraft: &Aircraft, + client: Option<&super::fs_azure::ContainerClient>, +) -> Result>, Box> { + let dates = super::DateIter { + from, + to, + increment: time::Duration::days(1), + }; + + let months = dates + .clone() + .map(|x| { + time::Date::from_calendar_date(x.year(), x.month(), 1).expect("day 1 never errors") + }) + .collect::>(); + + let tasks = months + .into_iter() + .map(|month| async move { month_positions(&month, aircraft, client).await }); + + let positions = futures::stream::iter(tasks) + // limit concurrent tasks + .buffered(1) + .try_collect::>() + .await?; + + // flatten positions so we can look days on them + let mut positions = positions.into_iter().flatten().collect::>(); + + Ok(dates + .map(|date| { + ( + date, + // we can .remove because dates are guaranteed to be unique (and avoids clone) + positions + .remove(&date) + .expect("That every date is covered on months; every date is unique"), + ) + }) + .collect()) +}