use std::path::PathBuf;
use std::sync::Arc;
use bytes::Bytes;
use dashmap::DashMap;
use ezu::core::TileId;
use ezu::graph::{build_graph, Cache, Graph};
use ezu::paint::host::{
build_dem_sources, build_raster_sources, BrushBankLoader, DemSourceRegistry,
RasterSourceRegistry,
};
use ezu::paint::nodes::default_registry;
use ezu::style::Document;
use serde::Serialize;
use tokio::sync::{broadcast, RwLock};
use crate::source::TileSource;
#[derive(Clone)]
pub struct AppState {
pub source: Option<Arc<TileSource>>,
pub source_name: Option<Arc<str>>,
pub style: Arc<RwLock<StyleSnapshot>>,
pub assets_dir: Arc<PathBuf>,
pub mvt_cache: Arc<DashMap<TileId, Bytes>>,
pub overzoom_levels: u8,
pub schema: Arc<serde_json::Value>,
pub events: broadcast::Sender<StyleReload>,
}
#[derive(Debug, Clone, Serialize)]
pub struct StyleReload {
pub version: u64,
pub text: String,
pub mtime_ms: i64,
}
pub struct StyleSnapshot {
pub doc: Document,
pub graph: Arc<Graph>,
pub pad: u32,
pub cache: Arc<Cache>,
pub assets: Arc<BrushBankLoader>,
pub dem_sources: Arc<DemSourceRegistry>,
pub raster_sources: Arc<RasterSourceRegistry>,
pub text: String,
pub version: u64,
}
impl StyleSnapshot {
pub async fn build(
text: String,
version: u64,
assets_dir: &std::path::Path,
) -> Result<Self, BuildSnapshotError> {
let doc = Document::from_json(&text).map_err(BuildSnapshotError::Parse)?;
let registry = default_registry();
let graph = build_graph(&doc, ®istry).map_err(BuildSnapshotError::Graph)?;
let mut loader = BrushBankLoader::new()
.with_dir(assets_dir.to_path_buf())
.with_images_dir(assets_dir.to_path_buf());
ezu::paint::host::prefetch_doc_assets(&doc, assets_dir, &mut loader)
.await
.map_err(BuildSnapshotError::Assets)?;
let dem_sources = Arc::new(build_dem_sources(&doc));
let raster_sources = Arc::new(build_raster_sources(&doc, Some(assets_dir.to_path_buf())));
let pad = crate::canvas_pad(&graph, &doc);
Ok(Self {
doc,
graph: Arc::new(graph),
pad,
cache: Arc::new(Cache::new()),
assets: Arc::new(loader),
dem_sources,
raster_sources,
text,
version,
})
}
}
#[derive(Debug, thiserror::Error)]
pub enum BuildSnapshotError {
#[error("parse: {0}")]
Parse(#[from] ezu::style::StyleError),
#[error("build graph: {0}")]
Graph(#[from] ezu::graph::BuildGraphError),
#[error("prefetch assets: {0}")]
Assets(String),
}
pub fn validate_text(text: &str) -> Result<(), BuildSnapshotError> {
let doc = Document::from_json(text).map_err(BuildSnapshotError::Parse)?;
let registry = default_registry();
build_graph(&doc, ®istry).map_err(BuildSnapshotError::Graph)?;
Ok(())
}
impl AppState {
pub fn new(
source: Option<TileSource>,
source_name: Option<String>,
snapshot: StyleSnapshot,
assets_dir: PathBuf,
overzoom_levels: u8,
) -> Self {
let schema = default_registry().document_schema();
let (events, _) = broadcast::channel(8);
Self {
source: source.map(Arc::new),
source_name: source_name.map(Arc::from),
style: Arc::new(RwLock::new(snapshot)),
assets_dir: Arc::new(assets_dir),
mvt_cache: Arc::new(DashMap::new()),
schema: Arc::new(schema),
events,
overzoom_levels,
}
}
}