config file ification

This commit is contained in:
core 2025-01-01 22:05:07 -05:00
parent aa512c3d97
commit 7bd7b30fec
Signed by: core
GPG key ID: FDBF740DADDCEECF
7 changed files with 96 additions and 8 deletions

2
Cargo.lock generated
View file

@ -2743,9 +2743,11 @@ dependencies = [
"ordered-float", "ordered-float",
"png", "png",
"reqwest", "reqwest",
"serde",
"thiserror 1.0.64", "thiserror 1.0.64",
"tikv-jemallocator", "tikv-jemallocator",
"tokio", "tokio",
"toml",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"wxbox-grib2", "wxbox-grib2",

16
config.toml Normal file
View file

@ -0,0 +1,16 @@
[sources.grib2.noaa_mrms_merged_composite_reflectivity_qc]
from = "https://mrms.ncep.noaa.gov/data/2D/HAWAII/MergedReflectivityQCComposite/MRMS_MergedReflectivityQCComposite.latest.grib2.gz"
needs_gzip = true
valid_for = 120
palette = """
Color: 10 164 164 255 100 100 192
Color: 20 64 128 255 32 64 128
Color: 30 0 255 0 0 128 0
Color: 40 255 255 0 255 128 0
Color: 50 255 0 0 160 0 0
Color: 60 255 0 255 128 0 128
Color: 70 255 255 255 128 128 128
Color: 80 128 128 128
"""
missing = -99.0
no_coverage = -999.0

View file

@ -19,6 +19,8 @@ mime = "0.3.17"
wxbox-grib2 = { version = "0.1", path = "../wxbox-grib2" } wxbox-grib2 = { version = "0.1", path = "../wxbox-grib2" }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = "0.3" tracing-subscriber = "0.3"
toml = "0.8"
serde = { version = "1", features = ["derive"] }
[dev-dependencies] [dev-dependencies]
approx = "0.5" approx = "0.5"

23
wxbox-tiler/src/config.rs Normal file
View file

@ -0,0 +1,23 @@
use std::collections::HashMap;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Config {
pub sources: Sources
}
#[derive(Deserialize)]
pub struct Sources {
pub grib2: HashMap<String, Grib2Source>
}
#[derive(Deserialize)]
pub struct Grib2Source {
pub from: String,
pub needs_gzip: bool,
pub valid_for: u64,
pub palette: String,
pub missing: Option<f64>,
pub range_folded: Option<f64>,
pub no_coverage: Option<f64>
}

View file

@ -1,32 +1,42 @@
pub(crate) mod sources; pub(crate) mod sources;
mod pixmap; mod pixmap;
mod config;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::env::args;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use std::time::SystemTime; use std::time::SystemTime;
use actix_web::{App, HttpServer}; use actix_web::{App, HttpServer};
use actix_web::web::Data; use actix_web::web::Data;
use wxbox_grib2::GribMessage; use wxbox_grib2::GribMessage;
use crate::config::Config;
pub struct AppState { pub struct AppState {
grib2_cache: RwLock<HashMap<String, Arc<RwLock<GribMessage>>>>, grib2_cache: RwLock<HashMap<String, Arc<RwLock<GribMessage>>>>,
grib2_cache_timestamps: RwLock<HashMap<String, SystemTime>> grib2_cache_timestamps: RwLock<HashMap<String, SystemTime>>,
config: Config
} }
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
let config_path = args().nth(1).unwrap();
let config_str = fs::read_to_string(config_path).unwrap();
let config: Config = toml::from_str(&config_str).unwrap();
let data = Data::new(AppState { let data = Data::new(AppState {
grib2_cache: RwLock::new(HashMap::new()), grib2_cache: RwLock::new(HashMap::new()),
grib2_cache_timestamps: RwLock::new(HashMap::new()) grib2_cache_timestamps: RwLock::new(HashMap::new()),
config
}); });
HttpServer::new(move || { HttpServer::new(move || {
App::new() App::new()
.service(sources::noaa::noaa_mrms_merged_composite_reflectivity_qc) .service(sources::grib2::grib2_source)
.app_data(data.clone()) .app_data(data.clone())
}) })
.bind(("::", 8080))? .bind(("::", 8080))?

View file

@ -3,12 +3,18 @@ use std::f64::consts::PI;
use std::io::{BufWriter, Cursor, Read}; use std::io::{BufWriter, Cursor, Read};
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime; use std::time::SystemTime;
use actix_web::error::UrlencodedError::ContentType;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use actix_web::web::Data;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use png::{BitDepth, ColorType, Encoder}; use png::{BitDepth, ColorType, Encoder};
use tokio::sync::RwLock; use tokio::sync::RwLock;
use wxbox_grib2::GribMessage; use wxbox_grib2::GribMessage;
use wxbox_grib2::wgs84::LatLong; use wxbox_grib2::wgs84::LatLong;
use wxbox_pal::{Color, ColorPalette, Palette}; use wxbox_pal::{Color, ColorPalette, Palette};
use crate::AppState;
use crate::config::Grib2Source;
use crate::pixmap::Pixmap; use crate::pixmap::Pixmap;
pub async fn needs_reload(lct: &RwLock<HashMap<String, SystemTime>>, lutkey: &String, valid_for: u64) -> bool { pub async fn needs_reload(lct: &RwLock<HashMap<String, SystemTime>>, lutkey: &String, valid_for: u64) -> bool {
@ -125,6 +131,35 @@ pub async fn render(xtile: f64, ytile: f64, z: i32, tilesize: usize, pal: Palett
buf buf
} }
#[actix_web::get("/grib2/{id}/{z}/{x}/{y}.png")]
pub async fn grib2_source(path: actix_web::web::Path<(String, i32, u32, u32)>, data: Data<AppState>) -> HttpResponse {
if let Some(known_source) = data.config.sources.grib2.get(&path.0) {
reload_if_required(
&known_source.from,
known_source.needs_gzip,
known_source.valid_for.into(),
&path.0,
&data.grib2_cache_timestamps,
&data.grib2_cache
).await;
let lct_reader = data.grib2_cache_timestamps.read().await;
if let Some(grib2) = data.grib2_cache.read().await.get(&path.0) {
HttpResponse::Ok()
.insert_header(actix_web::http::header::ContentType(mime::IMAGE_PNG))
// TODO: use the timestamp in the grib2 ID section
.insert_header(("x-wxbox-tiler-data-valid-time", lct_reader.get(&path.0).expect("impossible").duration_since(::std::time::UNIX_EPOCH).expect("time went backwards").as_secs().to_string()))
.insert_header(("Access-Control-Allow-Origin", "*"))
.insert_header(("Access-Control-Expose-Headers", "*"))
.insert_header(("Access-Control-Allow-Headers", "*"))
.body(crate::sources::grib2::render(path.2 as f64, path.3 as f64, path.1, 256, wxbox_pal::parser::parse(&known_source.palette).unwrap(), grib2, known_source.missing, known_source.range_folded, known_source.no_coverage).await)
} else {
HttpResponse::new(StatusCode::NOT_FOUND)
}
} else {
HttpResponse::new(StatusCode::NOT_FOUND)
}
}
/*
#[macro_export] #[macro_export]
macro_rules! grib2_handler { macro_rules! grib2_handler {
(mount $f:ident, at: $path:expr, from: $from:expr, needs_gzip: $needs_gzip:expr, valid_for: $valid_for:expr, palette: $pal:expr, missing: $missing:expr, range_folded: $rf:expr, no_coverage: $nc:expr) => { (mount $f:ident, at: $path:expr, from: $from:expr, needs_gzip: $needs_gzip:expr, valid_for: $valid_for:expr, palette: $pal:expr, missing: $missing:expr, range_folded: $rf:expr, no_coverage: $nc:expr) => {
@ -152,4 +187,4 @@ macro_rules! grib2_handler {
} }
} }
}; };
} }*/

View file

@ -1,13 +1,13 @@
use crate::grib2_handler; //use crate::grib2_handler;
/*
grib2_handler! { grib2_handler! {
mount noaa_mrms_merged_composite_reflectivity_qc, mount noaa_mrms_merged_composite_reflectivity_qc,
at: "/noaa_mrms_merged_composite_reflectivity_qc/{z}/{x}/{y}.png", at: "/noaa_mrms_merged_composite_reflectivity_qc/{z}/{x}/{y}.png",
from: "https://mrms.ncep.noaa.gov/data/2D/MergedReflectivityQCComposite/MRMS_MergedReflectivityQCComposite.latest.grib2.gz", from: "https://mrms.ncep.noaa.gov/data/2D/HAWAII/MergedReflectivityQCComposite/MRMS_MergedReflectivityQCComposite.latest.grib2.gz",
needs_gzip: true, needs_gzip: true,
valid_for: 120, valid_for: 120,
palette: wxbox_pal::parser::parse(wxbox_pal::default_palettes::DEFAULT_REFLECTIVITY_PALETTE).unwrap(), palette: wxbox_pal::parser::parse(wxbox_pal::default_palettes::DEFAULT_REFLECTIVITY_PALETTE).unwrap(),
missing: Some(-99.0), missing: Some(-99.0),
range_folded: None, range_folded: None,
no_coverage: Some(-999.0) no_coverage: Some(-999.0)
} }*/