chore: praise be the clippy gods
Some checks are pending
Verify Latest Dependencies / Verify Latest Dependencies (push) Waiting to run
build and test / wxbox - latest (push) Waiting to run

This commit is contained in:
core 2025-05-19 10:38:23 -04:00
parent fe4a47d6cc
commit e4dcb48878
9 changed files with 55 additions and 90 deletions

View file

@ -1,6 +1,3 @@
use std::{env, fs};
use std::hint::black_box;
use std::time::Instant;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use wxbox_ar2::parse;

View file

@ -1,3 +1,5 @@
#![warn(clippy::all)]
use nexrad_data::volume::File;
use nexrad_decode::messages::MessageContents;
use nexrad_decode::messages::digital_radar_data::{GenericDataBlock, RadialStatus};
@ -46,7 +48,6 @@ pub struct MomentData {
impl MomentData {
/// Values from this data moment corresponding to gates in the radial.
pub fn values(&self) -> Vec<MomentValue> {
let copied_values = self.values.iter().copied();
@ -67,9 +68,7 @@ impl MomentData {
}
/// The data moment value for a product in a radial's gate. The value may be a floating-point number
/// or a special case such as "below threshold" or "range folded".
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MomentValue {
@ -89,7 +88,7 @@ pub fn parse(input: Vec<u8>) -> nexrad_data::result::Result<Scan> {
let mut vcp: Option<u16> = None;
let mut radials = vec![];
let mut radial_chunks: Vec<nexrad_data::result::Result<(Vec<Radial>, Option<u16>)>> = file.records()
let radial_chunks: Vec<nexrad_data::result::Result<(Vec<Radial>, Option<u16>)>> = file.records()
.par_iter_mut()
.map(|record| {
let mut vcp = None;
@ -145,23 +144,23 @@ fn into_radial(
radial_status: message.header.radial_status(),
elevation_number: message.header.elevation_number,
elevation_number_degrees: message.header.elevation_angle,
reflectivity: message.reflectivity_data_block.map(|u| into_moment_data(u)),
velocity: message.velocity_data_block.map(|u| into_moment_data(u)),
reflectivity: message.reflectivity_data_block.map(into_moment_data),
velocity: message.velocity_data_block.map(into_moment_data),
spectrum_width: message
.spectrum_width_data_block
.map(|u| into_moment_data(u)),
.map(into_moment_data),
differential_reflectivity: message
.differential_reflectivity_data_block
.map(|u| into_moment_data(u)),
.map(into_moment_data),
differential_phase: message
.differential_phase_data_block
.map(|u| into_moment_data(u)),
.map(into_moment_data),
correlation_coefficient: message
.correlation_coefficient_data_block
.map(|u| into_moment_data(u)),
.map(into_moment_data),
specific_differential_phase: message
.specific_diff_phase_data_block
.map(|u| into_moment_data(u)),
.map(into_moment_data),
})
}

View file

@ -1,5 +1,4 @@
use std::{env, fs};
use std::fs::File;
use std::time::Instant;
use wxbox_ar2::parse;

View file

@ -1,6 +1,6 @@
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use std::sync::{LazyLock, OnceLock};
use std::sync::LazyLock;
#[derive(Deserialize, Debug)]
pub struct Wsr88dSite {
@ -30,7 +30,7 @@ where
{
let s: String = Deserialize::deserialize(deserializer)?;
let elevation = s.split(" ").nth(0).unwrap();
let elevation = s.split(" ").next().unwrap();
Ok(elevation.parse().unwrap())
}

View file

@ -1,7 +1,4 @@
use std::{env, fs};
use std::hint::black_box;
use std::time::Instant;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use wxbox_grib2::GribMessage;

View file

@ -2,28 +2,24 @@ use crate::AppState;
use crate::error::AppError;
use crate::tiles::{DataId, TileId};
use anyhow::{anyhow, bail};
use axum::Json;
use axum::extract::{Path, State};
use axum::http::{StatusCode, header};
use axum::http::header;
use axum::response::IntoResponse;
use flate2::read::GzDecoder;
use image::codecs::png::PngEncoder;
use image::{Rgba, RgbaImage};
use moka::future::Cache;
use rayon::iter::IntoParallelIterator;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::f64::consts::PI;
use std::fmt::Debug;
use std::io;
use std::io::{Cursor, ErrorKind};
use std::num::TryFromIntError;
use std::sync::Arc;
use axum::Json;
use tokio::io::AsyncReadExt;
use tracing::{debug, info_span};
use tracing::info_span;
use wxbox_grib2::GribMessage;
use wxbox_grib2::wgs84::LatLong;
use wxbox_pal::{ColorPalette, Palette};
use wxbox_pal::ColorPalette;
use rayon::iter::ParallelIterator;
use wxbox_common::{Grib2DataSource, GribMessageTimeMetadata, GribTileMetadata};
@ -35,13 +31,11 @@ pub type Grib2DataConfig = HashMap<String, Grib2DataSource>;
#[tracing::instrument(level = "info")]
pub async fn grib2_metadata(
Path((source)): Path<(String)>,
Path(source): Path<String>,
State(state): State<AppState>,
) -> Result<Json<wxbox_common::GribTileMetadata>, AppError> {
// is this even a valid data source?
let data_id = DataId {
source,
};
let data_id = DataId { source };
let Some(ds) = state.config.data.grib2.get(&data_id.source) else {
return Err(anyhow!("invalid/unknown grib2 state").into());
};
@ -185,10 +179,7 @@ async fn render_to_png(
let nearest_value = data.value_for(LatLong { lat, long }).map(|u| u as f64);
let color =
colorize(nearest_value, &data_source).unwrap_or(Rgba::from([0, 0, 0, 0]));
color
colorize(nearest_value, &data_source).unwrap_or(Rgba::from([0, 0, 0, 0]))
})
.collect::<Vec<_>>()
})

View file

@ -2,25 +2,22 @@ mod config;
mod error;
mod grib2;
mod nexrad;
mod tiles;
mod nexrad_list_response;
mod tiles;
use crate::config::Config;
use crate::grib2::{Grib2DataCache, Grib2TileCache, grib2_handler, grib2_metadata};
use crate::nexrad::{NexradDataCache, NexradTileCache, nexrad_handler};
use crate::tiles::{DataId, TileId};
use axum::Router;
use axum::http::Method;
use axum::routing::get;
use moka::future::Cache;
use std::env::args;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use axum::http::Method;
use tower_http::cors::{Any, CorsLayer};
use tracing_subscriber::EnvFilter;
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::util::SubscriberInitExt;
use wxbox_grib2::GribMessage;
#[derive(Clone)]
pub struct AppState {

View file

@ -1,11 +1,12 @@
use crate::AppState;
use crate::error::AppError;
use crate::nexrad_list_response::ListBucketResult;
use crate::tiles::{DataId, TileId};
use anyhow::{anyhow, bail};
use axum::extract::{Path, State};
use axum::http::{StatusCode, header};
use axum::http::header;
use axum::response::IntoResponse;
use flate2::read::GzDecoder;
use chrono::{Datelike, Utc};
use geographiclib::Geodesic;
use image::codecs::png::PngEncoder;
use image::{Rgba, RgbaImage};
@ -16,19 +17,13 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::f64::consts::PI;
use std::fmt::Debug;
use std::{fs, io};
use std::io::{Cursor, ErrorKind};
use std::num::TryFromIntError;
use std::io;
use std::io::ErrorKind;
use std::sync::Arc;
use chrono::{Datelike, Utc};
use tokio::io::AsyncReadExt;
use tracing::{debug, info_span};
use wxbox_ar2::sites::wsr88d::{SITES, Wsr88dSite};
use wxbox_ar2::{MomentValue, Radial, Scan, Sweep, parse};
use wxbox_grib2::GribMessage;
use wxbox_grib2::wgs84::LatLong;
use wxbox_pal::{ColorPalette, Palette};
use crate::nexrad_list_response::ListBucketResult;
use wxbox_pal::ColorPalette;
pub type NexradDataCache = Cache<DataId, Arc<wxbox_ar2::Scan>>;
pub type NexradTileCache = Cache<TileId, Arc<Vec<u8>>>;
@ -92,8 +87,14 @@ pub async fn nexrad_handler(
// we know we need to build the tile, so let's do that now
// it also returns it, so we can conveniently return it right now
let pixel_data =
render_to_png(state.nexrad_tile_cache.clone(), data, tile_id, &site, ds.clone()).await?;
let pixel_data = render_to_png(
state.nexrad_tile_cache.clone(),
data,
tile_id,
&site,
ds.clone(),
)
.await?;
Ok((
[(header::CONTENT_TYPE, "image/png")],
@ -104,23 +105,24 @@ pub async fn nexrad_handler(
async fn load_nexrad_data(
cache: NexradDataCache,
data_id: DataId,
data_source: NexradDataSource,
_data_source: NexradDataSource,
site: &str,
) -> anyhow::Result<Arc<Scan>> {
let _load_span = info_span!("load_nexrad_data");
let mut searchdate = Utc::now();
let client = reqwest::Client::new();
let mut url;
let url;
let mut days_went_back = 0;
'outer: loop {
let year = searchdate.year();
let month = searchdate.month();
let day = searchdate.day();
let listing_url = format!("https://noaa-nexrad-level2.s3.amazonaws.com/?list-type=2&delimiter=/&prefix={year}/{month:02}/{day:02}/{site}/");
let listing_url = format!(
"https://noaa-nexrad-level2.s3.amazonaws.com/?list-type=2&delimiter=/&prefix={year}/{month:02}/{day:02}/{site}/"
);
debug!("downloading listing from {}", listing_url);
let r = client.get(listing_url).send().await?;
if !r.status().is_success() {
@ -135,18 +137,20 @@ async fn load_nexrad_data(
// fake. continue
continue;
} else {
debug!("nexrad: found l2 file for {} date {}", site, file.LastModified);
debug!(
"nexrad: found l2 file for {} date {}",
site, file.LastModified
);
url = format!("https://noaa-nexrad-level2.s3.amazonaws.com/{}", file.Key);
break 'outer;
}
}
}
searchdate -= chrono::Duration::days(1);
days_went_back += 1;
if days_went_back > 7 {
bail!("no recent radar data");
}
searchdate -= chrono::Duration::days(1);
days_went_back += 1;
if days_went_back > 7 {
bail!("no recent radar data");
}
}
let client = reqwest::Client::new();
@ -169,15 +173,6 @@ async fn load_nexrad_data(
const TWO_PI: f64 = PI * 2.0;
const HALF_PI: f64 = PI / 2.0;
const A: f64 = 6_378.1370; // km
const B: f64 = 6_356.7523; // km
fn radius_at_latitude(phi: f64) -> f64 {
let top = (A.powi(2) * phi.cos()).powi(2) + (B.powi(2) * phi.sin()).powi(2);
let bottom = (A * phi.cos()).powi(2) + (B * phi.sin()).powi(2);
(top / bottom).sqrt()
}
fn calculate_inverse(
tile_x_times_tilesize: f64,
tile_y_times_tilesize: f64,
@ -241,7 +236,7 @@ async fn render_to_png(
let tile_x_times_tilesize = tile_id.x as f64 * tile_id.size as f64;
let tile_y_times_tilesize = tile_id.y as f64 * tile_id.size as f64;
let first_sweep = data.sweeps.get(0).unwrap();
let first_sweep = data.sweeps.first().unwrap();
let g = Geodesic::wgs84();
let radar = SITES.sites.get(site).unwrap();
@ -284,7 +279,7 @@ async fn render_to_png(
let data = &reflectivity.values;
if gate > data.len() || gate < 0 {
if gate > data.len() {
return colorize(None, &data_source).unwrap_or(Rgba::from([0, 0, 0, 0]));
}
@ -296,7 +291,7 @@ async fn render_to_png(
),
});
return colorize(color, &data_source).unwrap_or(Rgba::from([0, 0, 0, 0]));
colorize(color, &data_source).unwrap_or(Rgba::from([0, 0, 0, 0]))
})
.collect::<Vec<_>>()
})
@ -338,12 +333,7 @@ fn colorize(
Some(MomentValue::RangeFolded) => Rgba([119, 0, 125, 255]),
Some(MomentValue::Value(value)) => {
let color = wxbox_pal::parser::parse(&data_source.palette)?.colorize(value as f64);
Rgba([
color.red,
color.green,
color.blue,
color.alpha,
])
Rgba([color.red, color.green, color.blue, color.alpha])
}
None => Rgba([0, 0, 0, 30]),
})

View file

@ -3,16 +3,11 @@ use serde::Deserialize;
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)] // xml
pub struct ListBucketResult {
pub Name: String,
pub Prefix: String,
pub KeyCount: usize,
pub MaxKeys: usize,
pub Contents: Option<Vec<ListBucketResultContents>>,
}
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)] // xml
pub struct ListBucketResultContents {
pub Key: String,
pub LastModified: String
}
pub LastModified: String,
}