use clap::Parser;
use log::{debug, info, trace, warn, LevelFilter};
#[cfg(not(all(feature = "aws", feature = "decode")))]
fn main() {
println!("This example requires the \"aws\" and \"decode\" features to be enabled.");
}
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(default_value = "KDMX")]
site: String,
#[arg(default_value = "2022-03-05")]
date: String,
#[arg(default_value = "23:30")]
start_time: String,
#[arg(default_value = "23:30")]
stop_time: String,
}
#[cfg(all(feature = "aws", feature = "decode"))]
#[tokio::main]
async fn main() -> nexrad_data::result::Result<()> {
use chrono::{NaiveDate, NaiveTime};
use nexrad_data::aws::archive::{download_file, list_files};
use nexrad_data::volume::File;
use std::fs::create_dir;
use std::io::Read;
use std::io::Write;
use std::path::Path;
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
.filter_module("reqwest::connect", LevelFilter::Info)
.init();
let cli = Cli::parse();
let site = &cli.site;
let date = NaiveDate::parse_from_str(&cli.date, "%Y-%m-%d").expect("is valid date");
let start_time =
NaiveTime::parse_from_str(&cli.start_time, "%H:%M").expect("start is valid time");
let stop_time = NaiveTime::parse_from_str(&cli.stop_time, "%H:%M").expect("stop is valid time");
info!("Listing files for {} on {}...", site, date);
let file_ids = list_files(site, &date).await?;
if file_ids.is_empty() {
warn!("No files found for the specified date/site to download.");
return Ok(());
}
debug!("Found {} files.", file_ids.len());
let start_index = get_nearest_file_index(&file_ids, start_time);
debug!(
"Nearest file to start of {:?} is {:?}.",
start_time,
file_ids[start_index].name()
);
let stop_index = get_nearest_file_index(&file_ids, stop_time);
debug!(
"Nearest file to stop of {:?} is {:?}.",
stop_time,
file_ids[stop_index].name()
);
debug!("Downloading {} files...", stop_index - start_index + 1);
for file_id in file_ids
.iter()
.skip(start_index)
.take(stop_index - start_index + 1)
{
let file = if Path::new(&format!("downloads/{}", file_id.name())).exists() {
debug!("File \"{}\" already downloaded.", file_id.name());
let mut file =
std::fs::File::open(format!("downloads/{}", file_id.name())).expect("open file");
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).expect("read file");
File::new(buffer)
} else {
debug!("Downloading file \"{}\"...", file_id.name());
let file = download_file(file_id.clone()).await?;
if !Path::new("downloads").exists() {
trace!("Creating downloads directory...");
create_dir("downloads").expect("create downloads directory");
}
trace!("Writing file to disk as: {}", file_id.name());
let mut downloaded_file =
std::fs::File::create(format!("downloads/{}", file_id.name()))
.expect("create file");
downloaded_file
.write_all(file.data().as_slice())
.expect("write file");
file
};
trace!("Data file size (bytes): {}", file.data().len());
let records = file.records();
debug!(
"Volume with {} records. Header: {:?}",
records.len(),
file.header()
);
let mut messages = Vec::new();
for mut record in records {
debug!("Decoding record...");
if record.compressed() {
trace!("Decompressing LDM record...");
record = record.decompress().expect("Failed to decompress record");
}
messages.extend(record.messages()?.iter().cloned());
}
let summary = nexrad_decode::summarize::messages(messages.as_slice());
info!("Volume summary:\n{:#?}", summary);
}
Ok(())
}
#[cfg(feature = "aws")]
fn get_nearest_file_index(
files: &Vec<nexrad_data::aws::archive::Identifier>,
start_time: chrono::NaiveTime,
) -> usize {
let first_file = files.first().expect("find at least one file");
let first_file_time = first_file
.date_time()
.expect("file has valid date time")
.time();
let mut min_diff = first_file_time
.signed_duration_since(start_time)
.num_seconds()
.abs();
let mut min_index = 0;
for (index, file) in files.iter().skip(1).enumerate() {
let file_time = file.date_time().expect("file has valid date time").time();
let diff = file_time
.signed_duration_since(start_time)
.num_seconds()
.abs();
if diff < min_diff {
min_diff = diff;
min_index = index;
}
}
min_index
}