use std::collections::HashMap;
use std::fmt::Debug;
use async_trait::async_trait;
use martin_tile_utils::{TileCoord, TileData, TileInfo};
use tilejson::TileJSON;
use crate::CacheZoomRange;
use crate::tiles::catalog::CatalogSourceEntry;
use crate::tiles::{MartinCoreResult, Tile};
pub type UrlQuery = HashMap<String, String>;
#[async_trait]
pub trait Source: Send + Sync + Debug {
fn get_id(&self) -> &str;
fn get_tilejson(&self) -> &TileJSON;
fn get_tile_info(&self) -> TileInfo;
fn clone_source(&self) -> BoxedSource;
fn get_version(&self) -> Option<String> {
None
}
fn support_url_query(&self) -> bool {
false
}
fn benefits_from_concurrent_scraping(&self) -> bool {
false
}
fn cache_zoom(&self) -> CacheZoomRange;
async fn get_tile(
&self,
xyz: TileCoord,
url_query: Option<&UrlQuery>,
) -> MartinCoreResult<TileData>;
async fn get_tile_with_etag(
&self,
xyz: TileCoord,
url_query: Option<&UrlQuery>,
) -> MartinCoreResult<Tile> {
let data = self.get_tile(xyz, url_query).await?;
Ok(Tile::new_hash_etag(data, self.get_tile_info()))
}
fn is_valid_zoom(&self, zoom: u8) -> bool {
let tj = self.get_tilejson();
tj.minzoom.is_none_or(|minzoom| zoom >= minzoom)
&& tj.maxzoom.is_none_or(|maxzoom| zoom <= maxzoom)
}
fn get_catalog_entry(&self) -> CatalogSourceEntry {
let id = self.get_id();
let tilejson = self.get_tilejson();
let info = self.get_tile_info();
CatalogSourceEntry {
content_type: info.format.content_type().to_string(),
content_encoding: info.encoding.compression().map(ToString::to_string),
name: tilejson.name.as_ref().filter(|v| *v != id).cloned(),
description: tilejson.description.clone(),
attribution: tilejson.attribution.clone(),
}
}
}
pub type BoxedSource = Box<dyn Source>;
impl Clone for BoxedSource {
fn clone(&self) -> Self {
self.clone_source()
}
}