feat: ssr
This commit is contained in:
parent
9a714a9323
commit
74d9647689
7 changed files with 60 additions and 13 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -4972,6 +4972,20 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bytes",
|
||||
"http",
|
||||
"pin-project-lite",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
|
@ -6330,6 +6344,7 @@ dependencies = [
|
|||
"strum_macros 0.27.1",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"wxbox-ar2",
|
||||
|
|
|
@ -31,6 +31,18 @@
|
|||
img.onload = () => {
|
||||
map?.addImage('radar-rect-gray', img);
|
||||
};
|
||||
map.addSource('kcys-bref-0.5', {
|
||||
type: 'raster',
|
||||
tiles: [
|
||||
'http://localhost:3000/nexrad/base_reflectivity_halfdegree/KCYS/{z}/{x}/{y}@2x.png'
|
||||
],
|
||||
'tileSize': 512
|
||||
});
|
||||
map.addLayer({
|
||||
id: 'kcys',
|
||||
type: 'raster',
|
||||
source: 'kcys-bref-0.5'
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -87,6 +87,7 @@ pub fn parse(input: Vec<u8>) -> nexrad_data::result::Result<Scan> {
|
|||
let mut vcp = None;
|
||||
let mut radials = vec![];
|
||||
|
||||
println!("{:?}", file.header());
|
||||
for mut record in file.records() {
|
||||
if record.compressed() {
|
||||
record = record.decompress()?;
|
||||
|
|
|
@ -7,6 +7,7 @@ edition = "2024"
|
|||
# web server
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
axum = "0.8"
|
||||
tower-http = { version = "0.6", features = ["cors"]}
|
||||
|
||||
# caching
|
||||
moka = { version = "0.12", features = ["future"] }
|
||||
|
|
|
@ -15,8 +15,8 @@ Color: 80 128 128 128
|
|||
missing = -99.0
|
||||
no_coverage = -999.0
|
||||
|
||||
[data.nexrad.l2_reflectivity]
|
||||
from = "aaaa"
|
||||
[data.nexrad.base_reflectivity_halfdegree]
|
||||
from = "DS.p94r0"
|
||||
palette = """
|
||||
Color: 5 0x40 0xe8 0xe3
|
||||
Color: 10 0x26 0xa4 0xfa
|
||||
|
|
|
@ -14,6 +14,8 @@ 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::fmt::format::FmtSpan;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use wxbox_grib2::GribMessage;
|
||||
|
@ -58,11 +60,16 @@ async fn main() -> anyhow::Result<()> {
|
|||
config: Arc::new(config),
|
||||
};
|
||||
|
||||
let cors = CorsLayer::new()
|
||||
.allow_methods([Method::GET])
|
||||
.allow_origin(Any);
|
||||
|
||||
let app = Router::new()
|
||||
.route("/grib2/{source}/{z}/{x}/{y}", get(grib2_handler))
|
||||
.route("/grib2/{source}/metadata", get(grib2_metadata))
|
||||
.route("/nexrad/{source}/{z}/{x}/{y}", get(nexrad_handler))
|
||||
.with_state(state);
|
||||
.route("/nexrad/{source}/{site}/{z}/{x}/{y}", get(nexrad_handler))
|
||||
.with_state(state)
|
||||
.layer(cors);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("[::]:3000").await?;
|
||||
axum::serve(listener, app).await?;
|
||||
|
|
|
@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::collections::HashMap;
|
||||
use std::f64::consts::PI;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::{fs, io};
|
||||
use std::io::{Cursor, ErrorKind};
|
||||
use std::num::TryFromIntError;
|
||||
use std::sync::Arc;
|
||||
|
@ -46,7 +46,7 @@ impl Debug for NexradDataSource {
|
|||
|
||||
#[tracing::instrument(level = "info")]
|
||||
pub async fn nexrad_handler(
|
||||
Path((source, z, x, y)): Path<(String, usize, usize, String)>,
|
||||
Path((source, site, z, x, y)): Path<(String, String, usize, usize, String)>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
let mut y = y
|
||||
|
@ -59,7 +59,7 @@ pub async fn nexrad_handler(
|
|||
}
|
||||
let y: usize = y.parse()?;
|
||||
let tile_id = TileId {
|
||||
source,
|
||||
source: format!("{source}/{site}"),
|
||||
z,
|
||||
x,
|
||||
y,
|
||||
|
@ -73,7 +73,7 @@ pub async fn nexrad_handler(
|
|||
|
||||
// is this even a valid data source?
|
||||
let data_id = tile_id.data_id();
|
||||
let Some(ds) = state.config.data.nexrad.get(&data_id.source) else {
|
||||
let Some(ds) = state.config.data.nexrad.get(&source) else {
|
||||
return Err(anyhow!("invalid/unknown nexrad state").into());
|
||||
};
|
||||
|
||||
|
@ -82,7 +82,7 @@ pub async fn nexrad_handler(
|
|||
// lets check if we have the raw data
|
||||
let data = if !state.nexrad_data_cache.contains_key(&data_id) {
|
||||
// we don't, so let's start by starting a task for that
|
||||
load_nexrad_data(state.nexrad_data_cache, data_id, ds.clone()).await?
|
||||
load_nexrad_data(state.nexrad_data_cache, data_id, ds.clone(), &site).await?
|
||||
} else {
|
||||
state.nexrad_data_cache.get(&data_id).await.unwrap()
|
||||
};
|
||||
|
@ -90,7 +90,7 @@ 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, ds.clone()).await?;
|
||||
render_to_png(state.nexrad_tile_cache.clone(), data, tile_id, &site, ds.clone()).await?;
|
||||
|
||||
Ok((
|
||||
[(header::CONTENT_TYPE, "image/png")],
|
||||
|
@ -102,10 +102,21 @@ async fn load_nexrad_data(
|
|||
cache: NexradDataCache,
|
||||
data_id: DataId,
|
||||
data_source: NexradDataSource,
|
||||
site: &str,
|
||||
) -> anyhow::Result<Arc<Scan>> {
|
||||
let _load_span = info_span!("load_nexrad_data");
|
||||
|
||||
let bytes = DATA_BYTES.to_vec();
|
||||
// todo: find the correct
|
||||
let url = format!("https://noaa-nexrad-level2.s3.amazonaws.com/2025/05/15/KCYS/KCYS20250515_003010_V06");
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let r = client.get(url).send().await?;
|
||||
|
||||
if !r.status().is_success() {
|
||||
bail!("nexrad data failed to load: {}", r.status());
|
||||
}
|
||||
|
||||
let bytes = r.bytes().await?.to_vec();
|
||||
|
||||
let data = Arc::new(parse(bytes)?);
|
||||
|
||||
|
@ -175,7 +186,7 @@ async fn render_to_png(
|
|||
cache: NexradTileCache,
|
||||
data: Arc<Scan>,
|
||||
tile_id: TileId,
|
||||
|
||||
site: &str,
|
||||
data_source: NexradDataSource,
|
||||
) -> anyhow::Result<Arc<Vec<u8>>> {
|
||||
let span = info_span!("render_to_png");
|
||||
|
@ -192,7 +203,7 @@ async fn render_to_png(
|
|||
let first_sweep = data.sweeps.get(0).unwrap();
|
||||
let g = Geodesic::wgs84();
|
||||
|
||||
let radar = SITES.sites.get("KCRP").unwrap();
|
||||
let radar = SITES.sites.get(site).unwrap();
|
||||
|
||||
drop(prep_span);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue