has issues
This commit is contained in:
parent
2e112d7398
commit
c645b0f1d4
96 changed files with 2147083 additions and 5787 deletions
|
|
@ -19,7 +19,7 @@ mod routes;
|
|||
mod state;
|
||||
pub mod utils;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
@ -167,6 +167,18 @@ struct Cli {
|
|||
#[arg(long)]
|
||||
tiles: PathBuf,
|
||||
|
||||
/// Optional PMTiles raster overlay for high-resolution strategic noise.
|
||||
#[arg(long, env = "NOISE_OVERLAY_TILES")]
|
||||
noise_overlay_tiles: Option<PathBuf>,
|
||||
|
||||
/// Optional PMTiles vector overlay for crime heatmap points.
|
||||
#[arg(long, env = "CRIME_HOTSPOT_TILES")]
|
||||
crime_hotspot_tiles: Option<PathBuf>,
|
||||
|
||||
/// Optional PMTiles vector overlay for Trees Outside Woodland polygons.
|
||||
#[arg(long, env = "TREE_OVERLAY_TILES")]
|
||||
tree_overlay_tiles: Option<PathBuf>,
|
||||
|
||||
/// Path to the frontend dist directory (optional; disables static serving and OG injection when omitted)
|
||||
#[arg(long)]
|
||||
dist: Option<PathBuf>,
|
||||
|
|
@ -207,6 +219,10 @@ struct Cli {
|
|||
#[arg(long, env = "ACTUAL_LISTINGS_PATH")]
|
||||
actual_listings_path: Option<PathBuf>,
|
||||
|
||||
/// Optional path to the per-LSOA per-year crime parquet (display-only side table for the right pane).
|
||||
#[arg(long, env = "CRIME_BY_YEAR_PATH")]
|
||||
crime_by_year_path: Option<PathBuf>,
|
||||
|
||||
/// Google Maps API key for Street View metadata lookups
|
||||
#[arg(long, env = "GOOGLE_MAPS_API_KEY")]
|
||||
google_maps_api_key: String,
|
||||
|
|
@ -280,6 +296,36 @@ async fn capture_server_error_responses(
|
|||
response
|
||||
}
|
||||
|
||||
async fn init_optional_tile_reader(
|
||||
label: &'static str,
|
||||
path: Option<&PathBuf>,
|
||||
) -> anyhow::Result<Option<Arc<routes::TileReader>>> {
|
||||
let Some(path) = path else {
|
||||
info!("{label} overlay tiles not configured");
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if !path.exists() {
|
||||
bail!("{label} overlay PMTiles not found: {}", path.display());
|
||||
}
|
||||
|
||||
info!("Loading {label} overlay PMTiles from {}", path.display());
|
||||
Ok(Some(Arc::new(routes::init_tile_reader(path).await?)))
|
||||
}
|
||||
|
||||
fn configured_or_default_overlay_path(
|
||||
configured: &Option<PathBuf>,
|
||||
tiles_path: &Path,
|
||||
file_name: &str,
|
||||
) -> Option<PathBuf> {
|
||||
if let Some(path) = configured {
|
||||
return Some(path.clone());
|
||||
}
|
||||
|
||||
let default_path = tiles_path.parent()?.join(file_name);
|
||||
default_path.exists().then_some(default_path)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
|
@ -424,6 +470,29 @@ async fn main() -> anyhow::Result<()> {
|
|||
let tile_reader = Arc::new(routes::init_tile_reader(tiles_path).await?);
|
||||
info!("PMTiles loaded successfully");
|
||||
|
||||
let noise_overlay_tiles = configured_or_default_overlay_path(
|
||||
&cli.noise_overlay_tiles,
|
||||
tiles_path,
|
||||
"noise_lden_10m.pmtiles",
|
||||
);
|
||||
let crime_hotspot_tiles = configured_or_default_overlay_path(
|
||||
&cli.crime_hotspot_tiles,
|
||||
tiles_path,
|
||||
"crime_hotspots.pmtiles",
|
||||
);
|
||||
let tree_overlay_tiles = configured_or_default_overlay_path(
|
||||
&cli.tree_overlay_tiles,
|
||||
tiles_path,
|
||||
"trees_outside_woodlands.pmtiles",
|
||||
);
|
||||
|
||||
let noise_overlay_reader =
|
||||
init_optional_tile_reader("Noise", noise_overlay_tiles.as_ref()).await?;
|
||||
let crime_hotspot_reader =
|
||||
init_optional_tile_reader("Crime hotspots", crime_hotspot_tiles.as_ref()).await?;
|
||||
let tree_overlay_reader =
|
||||
init_optional_tile_reader("Trees outside woodland", tree_overlay_tiles.as_ref()).await?;
|
||||
|
||||
let feature_name_to_index: rustc_hash::FxHashMap<String, usize> = property_data
|
||||
.feature_names
|
||||
.iter()
|
||||
|
|
@ -550,6 +619,18 @@ async fn main() -> anyhow::Result<()> {
|
|||
None
|
||||
};
|
||||
|
||||
let crime_by_year = if let Some(path) = cli.crime_by_year_path.as_ref() {
|
||||
if !path.exists() {
|
||||
bail!("Crime-by-year parquet not found: {}", path.display());
|
||||
}
|
||||
let data = data::CrimeByYearData::load(path)?;
|
||||
trim_allocator("crime-by-year load");
|
||||
Arc::new(data)
|
||||
} else {
|
||||
info!("CRIME_BY_YEAR_PATH not set; crime-over-time chart disabled");
|
||||
Arc::new(data::CrimeByYearData::empty())
|
||||
};
|
||||
|
||||
let app_state = AppState {
|
||||
data: property_data,
|
||||
grid,
|
||||
|
|
@ -576,6 +657,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
gemini_model: cli.gemini_model,
|
||||
travel_time_store,
|
||||
actual_listings,
|
||||
crime_by_year,
|
||||
token_cache,
|
||||
superuser_token_cache,
|
||||
share_cache,
|
||||
|
|
@ -610,6 +692,9 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
let reader_tile = tile_reader.clone();
|
||||
let reader_style = tile_reader.clone();
|
||||
let reader_noise_overlay = noise_overlay_reader.clone();
|
||||
let reader_crime_hotspot = crime_hotspot_reader.clone();
|
||||
let reader_tree_overlay = tree_overlay_reader.clone();
|
||||
let public_url_tiles = initial_state.public_url.clone();
|
||||
|
||||
let api = Router::new()
|
||||
|
|
@ -773,6 +858,42 @@ async fn main() -> anyhow::Result<()> {
|
|||
})
|
||||
.layer(ConcurrencyLimitLayer::new(20)),
|
||||
)
|
||||
.route(
|
||||
"/api/overlays/noise/{z}/{x}/{y}",
|
||||
get(move |path| {
|
||||
routes::get_overlay_tile(
|
||||
reader_noise_overlay.clone(),
|
||||
routes::OverlayTileFormat::RasterPng,
|
||||
"noise",
|
||||
path,
|
||||
)
|
||||
})
|
||||
.layer(ConcurrencyLimitLayer::new(30)),
|
||||
)
|
||||
.route(
|
||||
"/api/overlays/crime-hotspots/{z}/{x}/{y}",
|
||||
get(move |path| {
|
||||
routes::get_overlay_tile(
|
||||
reader_crime_hotspot.clone(),
|
||||
routes::OverlayTileFormat::VectorMvtGzip,
|
||||
"crime-hotspots",
|
||||
path,
|
||||
)
|
||||
})
|
||||
.layer(ConcurrencyLimitLayer::new(30)),
|
||||
)
|
||||
.route(
|
||||
"/api/overlays/trees-outside-woodlands/{z}/{x}/{y}",
|
||||
get(move |path| {
|
||||
routes::get_overlay_tile(
|
||||
reader_tree_overlay.clone(),
|
||||
routes::OverlayTileFormat::VectorMvtGzip,
|
||||
"trees-outside-woodlands",
|
||||
path,
|
||||
)
|
||||
})
|
||||
.layer(ConcurrencyLimitLayer::new(30)),
|
||||
)
|
||||
.route("/health", get(|| async { "ok" }))
|
||||
.route(
|
||||
"/metrics",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue