Skip to content

Commit

Permalink
Implement sprite catalog reporting
Browse files Browse the repository at this point in the history
The `/catalog` now shows available sprites, which also paves way for the future font support.

Lots of small refactorings to streamline tile source management.  Now each tile source can produce its own catalog entry, making the whole thing much simpler.
  • Loading branch information
nyurik committed Oct 19, 2023
1 parent addefbd commit 334ba53
Show file tree
Hide file tree
Showing 17 changed files with 271 additions and 233 deletions.
37 changes: 16 additions & 21 deletions martin/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ use crate::file_config::{resolve_files, FileConfigEnum};
use crate::mbtiles::MbtSource;
use crate::pg::PgConfig;
use crate::pmtiles::PmtSource;
use crate::source::Sources;
use crate::sprites::{resolve_sprites, SpriteSources};
use crate::source::{TileInfoSources, TileSources};
use crate::sprites::SpriteSources;
use crate::srv::SrvConfig;
use crate::utils::{IdResolver, OneOrMany, Result};
use crate::Error::{ConfigLoadError, ConfigParseError, NoSources};
use crate::{IdResolver, OneOrMany, Result};

pub type UnrecognizedValues = HashMap<String, serde_yaml::Value>;

pub struct AllSources {
pub sources: Sources,
pub struct ServerState {
pub tiles: TileSources,
pub sprites: SpriteSources,
}

Expand Down Expand Up @@ -90,16 +90,24 @@ impl Config {
}
}

pub async fn resolve(&mut self, idr: IdResolver) -> Result<AllSources> {
pub async fn resolve(&mut self, idr: IdResolver) -> Result<ServerState> {
Ok(ServerState {
tiles: self.resolve_tile_sources(idr).await?,
sprites: SpriteSources::resolve(&mut self.sprites)?,
})
}

async fn resolve_tile_sources(&mut self, idr: IdResolver) -> Result<TileSources> {
let create_pmt_src = &mut PmtSource::new_box;
let create_mbt_src = &mut MbtSource::new_box;
let mut sources: Vec<Pin<Box<dyn Future<Output = Result<TileInfoSources>>>>> = Vec::new();

let mut sources: Vec<Pin<Box<dyn Future<Output = Result<Sources>>>>> = Vec::new();
if let Some(v) = self.postgres.as_mut() {
for s in v.iter_mut() {
sources.push(Box::pin(s.resolve(idr.clone())));
}
}

if self.pmtiles.is_some() {
let val = resolve_files(&mut self.pmtiles, idr.clone(), "pmtiles", create_pmt_src);
sources.push(Box::pin(val));
Expand All @@ -110,20 +118,7 @@ impl Config {
sources.push(Box::pin(val));
}

// Minor in-efficiency:
// Sources are added to a BTreeMap, then iterated over into a sort structure and convert back to a BTreeMap.
// Ideally there should be a vector of values, which is then sorted (in-place?) and converted to a BTreeMap.
Ok(AllSources {
sources: try_join_all(sources)
.await?
.into_iter()
.fold(Sources::default(), |mut acc, hashmap| {
acc.extend(hashmap);
acc
})
.sort(),
sprites: resolve_sprites(&mut self.sprites)?,
})
Ok(TileSources::new(try_join_all(sources).await?))
}
}

Expand Down
14 changes: 7 additions & 7 deletions martin/src/file_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};

use crate::config::{copy_unrecognized_config, UnrecognizedValues};
use crate::file_config::FileError::{InvalidFilePath, InvalidSourceFilePath, IoError};
use crate::source::{Source, Sources};
use crate::source::{Source, TileInfoSources};
use crate::utils::{sorted_opt_map, Error, IdResolver, OneOrMany};
use crate::OneOrMany::{Many, One};

Expand Down Expand Up @@ -152,7 +152,7 @@ pub async fn resolve_files<Fut>(
idr: IdResolver,
extension: &str,
create_source: &mut impl FnMut(String, PathBuf) -> Fut,
) -> Result<Sources, Error>
) -> Result<TileInfoSources, Error>
where
Fut: Future<Output = Result<Box<dyn Source>, FileError>>,
{
Expand All @@ -166,16 +166,16 @@ async fn resolve_int<Fut>(
idr: IdResolver,
extension: &str,
create_source: &mut impl FnMut(String, PathBuf) -> Fut,
) -> Result<Sources, FileError>
) -> Result<TileInfoSources, FileError>
where
Fut: Future<Output = Result<Box<dyn Source>, FileError>>,
{
let Some(cfg) = config else {
return Ok(Sources::default());
return Ok(TileInfoSources::default());
};
let cfg = cfg.extract_file_config();

let mut results = Sources::default();
let mut results = TileInfoSources::default();
let mut configs = HashMap::new();
let mut files = HashSet::new();
let mut directories = Vec::new();
Expand All @@ -198,7 +198,7 @@ where
FileConfigSrc::Obj(pmt) => pmt.path,
FileConfigSrc::Path(path) => path,
};
results.insert(id.clone(), create_source(id, path).await?);
results.push(create_source(id, path).await?);
}
}

Expand Down Expand Up @@ -244,7 +244,7 @@ where
FileConfigSrc::Obj(pmt) => pmt.path,
FileConfigSrc::Path(path) => path,
};
results.insert(id.clone(), create_source(id, path).await?);
results.push(create_source(id, path).await?);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions martin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod source;
pub mod sprites;
pub mod srv;
mod utils;
pub use utils::Xyz;

#[cfg(test)]
#[path = "utils/test_utils.rs"]
Expand All @@ -27,8 +28,8 @@ mod test_utils;
// Must make it accessible as carte::Env from both places when testing.
#[cfg(test)]
pub use crate::args::Env;
pub use crate::config::{read_config, Config};
pub use crate::source::{Source, Sources, Xyz};
pub use crate::config::{read_config, Config, ServerState};
pub use crate::source::Source;
pub use crate::utils::{
decode_brotli, decode_gzip, BoolOrObject, Error, IdResolver, OneOrMany, Result,
};
Expand Down
13 changes: 6 additions & 7 deletions martin/src/mbtiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use tilejson::TileJSON;
use crate::file_config::FileError;
use crate::file_config::FileError::{AquireConnError, InvalidMetadata, IoError};
use crate::source::{Tile, UrlQuery};
use crate::utils::is_valid_zoom;
use crate::{Error, Source, Xyz};

#[derive(Clone)]
Expand Down Expand Up @@ -66,8 +65,12 @@ impl MbtSource {

#[async_trait]
impl Source for MbtSource {
fn get_tilejson(&self) -> TileJSON {
self.tilejson.clone()
fn get_id(&self) -> &str {
&self.id
}

fn get_tilejson(&self) -> &TileJSON {
&self.tilejson
}

fn get_tile_info(&self) -> TileInfo {
Expand All @@ -78,10 +81,6 @@ impl Source for MbtSource {
Box::new(self.clone())
}

fn is_valid_zoom(&self, zoom: u8) -> bool {
is_valid_zoom(zoom, self.tilejson.minzoom, self.tilejson.maxzoom)
}

fn support_url_query(&self) -> bool {
false
}
Expand Down
4 changes: 2 additions & 2 deletions martin/src/pg/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::pg::config_function::FuncInfoSources;
use crate::pg::config_table::TableInfoSources;
use crate::pg::configurator::PgBuilder;
use crate::pg::Result;
use crate::source::Sources;
use crate::source::TileInfoSources;
use crate::utils::{on_slow, sorted_opt_map, BoolOrObject, IdResolver, OneOrMany};

pub trait PgInfo {
Expand Down Expand Up @@ -111,7 +111,7 @@ impl PgConfig {
Ok(res)
}

pub async fn resolve(&mut self, id_resolver: IdResolver) -> crate::Result<Sources> {
pub async fn resolve(&mut self, id_resolver: IdResolver) -> crate::Result<TileInfoSources> {
let pg = PgBuilder::new(self, id_resolver).await?;
let inst_tables = on_slow(pg.instantiate_tables(), Duration::from_secs(5), || {
if pg.disable_bounds() {
Expand Down
28 changes: 15 additions & 13 deletions martin/src/pg/configurator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::pg::table_source::{
use crate::pg::utils::{find_info, find_kv_ignore_case, normalize_key, InfoMap};
use crate::pg::PgError::InvalidTableExtent;
use crate::pg::Result;
use crate::source::Sources;
use crate::source::TileInfoSources;
use crate::utils::{BoolOrObject, IdResolver, OneOrMany};

pub type SqlFuncInfoMapMap = InfoMap<InfoMap<(PgSqlInfo, FunctionInfo)>>;
Expand Down Expand Up @@ -73,7 +73,7 @@ impl PgBuilder {

// FIXME: this function has gotten too long due to the new formatting rules, need to be refactored
#[allow(clippy::too_many_lines)]
pub async fn instantiate_tables(&self) -> Result<(Sources, TableInfoSources)> {
pub async fn instantiate_tables(&self) -> Result<(TileInfoSources, TableInfoSources)> {
let mut db_tables_info = query_available_tables(&self.pool).await?;

// Match configured sources with the discovered ones and add them to the pending list.
Expand Down Expand Up @@ -170,7 +170,7 @@ impl PgBuilder {
}
}

let mut res = Sources::default();
let mut res = TileInfoSources::default();
let mut info_map = TableInfoSources::new();
let pending = join_all(pending).await;
for src in pending {
Expand All @@ -190,9 +190,9 @@ impl PgBuilder {
Ok((res, info_map))
}

pub async fn instantiate_functions(&self) -> Result<(Sources, FuncInfoSources)> {
pub async fn instantiate_functions(&self) -> Result<(TileInfoSources, FuncInfoSources)> {
let mut db_funcs_info = query_available_function(&self.pool).await?;
let mut res = Sources::default();
let mut res = TileInfoSources::default();
let mut info_map = FuncInfoSources::new();
let mut used = HashSet::<(&str, &str)>::new();

Expand Down Expand Up @@ -262,14 +262,16 @@ impl PgBuilder {
self.id_resolver.resolve(id, signature)
}

fn add_func_src(&self, sources: &mut Sources, id: String, info: &impl PgInfo, sql: PgSqlInfo) {
let source = PgSource::new(
id.clone(),
sql,
info.to_tilejson(id.clone()),
self.pool.clone(),
);
sources.insert(id, Box::new(source));
fn add_func_src(
&self,
sources: &mut TileInfoSources,
id: String,
info: &impl PgInfo,
sql: PgSqlInfo,
) {
let tilejson = info.to_tilejson(id.clone());
let source = PgSource::new(id, sql, tilejson, self.pool.clone());
sources.push(Box::new(source));
}
}

Expand Down
16 changes: 8 additions & 8 deletions martin/src/pg/pg_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use tilejson::TileJSON;
use crate::pg::pool::PgPool;
use crate::pg::utils::query_to_json;
use crate::pg::PgError::{GetTileError, GetTileWithQueryError, PrepareQueryError};
use crate::source::{Source, Tile, UrlQuery, Xyz};
use crate::utils::{is_valid_zoom, Result};
use crate::source::{Source, Tile, UrlQuery};
use crate::{Result, Xyz};

#[derive(Clone, Debug)]
pub struct PgSource {
Expand All @@ -36,8 +36,12 @@ impl PgSource {

#[async_trait]
impl Source for PgSource {
fn get_tilejson(&self) -> TileJSON {
self.tilejson.clone()
fn get_id(&self) -> &str {
&self.id
}

fn get_tilejson(&self) -> &TileJSON {
&self.tilejson
}

fn get_tile_info(&self) -> TileInfo {
Expand All @@ -48,10 +52,6 @@ impl Source for PgSource {
Box::new(self.clone())
}

fn is_valid_zoom(&self, zoom: u8) -> bool {
is_valid_zoom(zoom, self.tilejson.minzoom, self.tilejson.maxzoom)
}

fn support_url_query(&self) -> bool {
self.info.use_url_query
}
Expand Down
17 changes: 8 additions & 9 deletions martin/src/pmtiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ use tilejson::TileJSON;

use crate::file_config::FileError;
use crate::file_config::FileError::{InvalidMetadata, IoError};
use crate::source::{Source, Tile, UrlQuery, Xyz};
use crate::utils::is_valid_zoom;
use crate::Error;
use crate::source::{Source, Tile, UrlQuery};
use crate::{Error, Xyz};

#[derive(Clone)]
pub struct PmtSource {
Expand Down Expand Up @@ -114,8 +113,12 @@ impl PmtSource {

#[async_trait]
impl Source for PmtSource {
fn get_tilejson(&self) -> TileJSON {
self.tilejson.clone()
fn get_id(&self) -> &str {
&self.id
}

fn get_tilejson(&self) -> &TileJSON {
&self.tilejson
}

fn get_tile_info(&self) -> TileInfo {
Expand All @@ -126,10 +129,6 @@ impl Source for PmtSource {
Box::new(self.clone())
}

fn is_valid_zoom(&self, zoom: u8) -> bool {
is_valid_zoom(zoom, self.tilejson.minzoom, self.tilejson.maxzoom)
}

fn support_url_query(&self) -> bool {
false
}
Expand Down
Loading

0 comments on commit 334ba53

Please sign in to comment.