|
| 1 | +use std::collections::HashMap; |
| 2 | + |
1 | 3 | use serde::Deserialize; |
2 | 4 |
|
3 | | -use superstac_core::models::{ |
4 | | - catalog::CatalogConfig, |
5 | | - provider::CatalogProviderConfig, |
| 5 | +use superstac_core::{errors::{SuperSTACError, ValidationError}, models::{ |
| 6 | + catalog::{Catalog, CatalogSettings, get_default_health_status}, |
| 7 | + provider::CatalogProvider, |
6 | 8 | settings::Settings, |
7 | | -}; |
| 9 | +}, utils::{get_date_time, parse_url, validate_identifier}}; |
| 10 | + |
8 | 11 |
|
9 | | -/// Configuration for SuperSTAC, Spatial Temporal Asset Catalog services |
| 12 | +/// Configuration for SuperSTAC. |
10 | 13 | #[derive(Debug, Deserialize)] |
11 | 14 | pub struct SuperStacConfig { |
12 | 15 | pub catalogs: Vec<CatalogConfig>, |
13 | 16 | pub providers: Vec<CatalogProviderConfig>, |
14 | 17 | pub settings: Settings, |
15 | 18 | } |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | +/// A data structure for a STAC catalog from the YAML file. |
| 23 | +#[derive(Debug, Deserialize)] |
| 24 | +pub struct CatalogConfig { |
| 25 | + pub id: String, |
| 26 | + pub provider: Option<String>, |
| 27 | + pub title: Option<String>, |
| 28 | + pub url: Option<String>, |
| 29 | + pub description: Option<String>, |
| 30 | + pub settings: Option<CatalogSettings>, |
| 31 | + /// Maps canonical collection IDs to this catalog's local collection IDs. |
| 32 | + /// E.g. `sentinel-2-l2a: S2MSI2A` on a CDSE-style catalog. |
| 33 | + pub collection_aliases: Option<HashMap<String, String>>, |
| 34 | + /// Per-collection asset rename rules, keyed by canonical collection ID. |
| 35 | + /// Inner map: canonical asset key -> this catalog's local asset key. |
| 36 | + /// E.g. `{ "sentinel-2-l2a": { "blue": "B02", "green": "B03" } }`. |
| 37 | + pub asset_aliases: Option<HashMap<String, HashMap<String, String>>>, |
| 38 | +} |
| 39 | + |
| 40 | +impl TryFrom<CatalogConfig> for Catalog { |
| 41 | + type Error = SuperSTACError; |
| 42 | + |
| 43 | + fn try_from(cfg: CatalogConfig) -> Result<Self, Self::Error> { |
| 44 | + validate_identifier(&cfg.id)?; |
| 45 | + |
| 46 | + let url = match cfg.url { |
| 47 | + Some(w) => { |
| 48 | + parse_url(&w).map_err(|e| ValidationError::InvalidUrl(e.to_string()))?; |
| 49 | + Some(w) |
| 50 | + } |
| 51 | + None => None, |
| 52 | + }; |
| 53 | + |
| 54 | + Ok(Self { |
| 55 | + id: cfg.id, |
| 56 | + provider: None, |
| 57 | + title: cfg.title, |
| 58 | + url: url.clone().unwrap(), |
| 59 | + description: cfg.description, |
| 60 | + settings: cfg.settings.unwrap_or(CatalogSettings::default()), |
| 61 | + health_status: get_default_health_status(url.unwrap()), |
| 62 | + capabilities: None, |
| 63 | + collection_aliases: cfg.collection_aliases.unwrap_or_default(), |
| 64 | + asset_aliases: cfg.asset_aliases.unwrap_or_default(), |
| 65 | + supported_collections: None, |
| 66 | + created_at: Some(get_date_time()), |
| 67 | + updated_at: None, |
| 68 | + }) |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | + |
| 73 | +/// YAML-deserialization shape for a provider entry. Converted to |
| 74 | +/// [`CatalogProvider`] via `TryFrom`. |
| 75 | +#[derive(Debug, Deserialize)] |
| 76 | +pub struct CatalogProviderConfig { |
| 77 | + pub id: String, |
| 78 | + pub name: Option<String>, |
| 79 | + pub description: Option<String>, |
| 80 | + pub logo_url: Option<String>, |
| 81 | + pub website_url: Option<String>, |
| 82 | + // Disabling this for now, because it's probably better to have it in the catalog. |
| 83 | + // pub stac_version: Option<String>, |
| 84 | + pub catalog_ids: Option<Vec<String>>, |
| 85 | +} |
| 86 | + |
| 87 | +impl TryFrom<CatalogProviderConfig> for CatalogProvider { |
| 88 | + type Error = SuperSTACError; |
| 89 | + |
| 90 | + fn try_from(cfg: CatalogProviderConfig) -> Result<Self, Self::Error> { |
| 91 | + validate_identifier(&cfg.id)?; |
| 92 | + |
| 93 | + let website_url = match cfg.website_url { |
| 94 | + Some(w) => { |
| 95 | + parse_url(&w).map_err(|e| ValidationError::InvalidUrl(e.to_string()))?; |
| 96 | + Some(w) |
| 97 | + } |
| 98 | + None => None, |
| 99 | + }; |
| 100 | + |
| 101 | + let logo_url = match cfg.logo_url { |
| 102 | + Some(l) => { |
| 103 | + parse_url(&l).map_err(|e| ValidationError::InvalidUrl(e.to_string()))?; |
| 104 | + Some(l) |
| 105 | + } |
| 106 | + None => None, |
| 107 | + }; |
| 108 | + |
| 109 | + // let stac_version = cfg |
| 110 | + // .stac_version |
| 111 | + // .ok_or_else(|| ValidationError::MissingField("stac_version".into()))?; |
| 112 | + |
| 113 | + Ok(Self { |
| 114 | + id: cfg.id, |
| 115 | + name: cfg.name, |
| 116 | + description: cfg.description, |
| 117 | + website_url, |
| 118 | + logo_url, |
| 119 | + // stac_version: Some(stac_version), |
| 120 | + catalog_ids: None, |
| 121 | + created_at: Some(get_date_time()), |
| 122 | + updated_at: None, |
| 123 | + }) |
| 124 | + } |
| 125 | +} |
0 commit comments