ogcapi_services/
state.rs

1use std::sync::{Arc, RwLock};
2
3#[cfg(feature = "edr")]
4use ogcapi_drivers::EdrQuerier;
5#[cfg(feature = "features")]
6use ogcapi_drivers::FeatureTransactions;
7#[cfg(feature = "processes")]
8use ogcapi_drivers::JobHandler;
9#[cfg(feature = "styles")]
10use ogcapi_drivers::StyleTransactions;
11#[cfg(feature = "tiles")]
12use ogcapi_drivers::TileTransactions;
13
14use ogcapi_drivers::{CollectionTransactions, postgres::Db};
15#[cfg(feature = "processes")]
16use ogcapi_processes::Processor;
17use ogcapi_types::common::{Conformance, LandingPage};
18
19use crate::{Config, ConfigParser, OpenAPI, openapi::OPENAPI};
20
21/// Application state
22#[derive(Clone)]
23pub struct AppState {
24    pub root: Arc<RwLock<LandingPage>>,
25    pub conformance: Arc<RwLock<Conformance>>,
26    pub openapi: OpenAPI,
27    pub drivers: Arc<Drivers>,
28    pub db: Db,
29    #[cfg(feature = "stac")]
30    pub s3: ogcapi_drivers::s3::S3,
31    #[cfg(feature = "processes")]
32    pub processors: Arc<RwLock<std::collections::HashMap<String, Box<dyn Processor>>>>,
33}
34
35// TODO: Introduce service trait
36pub struct Drivers {
37    pub collections: Box<dyn CollectionTransactions>,
38    #[cfg(feature = "features")]
39    pub features: Box<dyn FeatureTransactions>,
40    #[cfg(feature = "edr")]
41    pub edr: Box<dyn EdrQuerier>,
42    #[cfg(feature = "processes")]
43    pub jobs: Box<dyn JobHandler>,
44    #[cfg(feature = "styles")]
45    pub styles: Box<dyn StyleTransactions>,
46    #[cfg(feature = "tiles")]
47    pub tiles: Box<dyn TileTransactions>,
48}
49
50impl AppState {
51    pub async fn new() -> Self {
52        let config = Config::parse();
53        AppState::new_from(&config).await
54    }
55
56    pub async fn new_from(config: &Config) -> Self {
57        let openapi = if let Some(path) = &config.openapi {
58            OpenAPI::from_path(path).unwrap()
59        } else {
60            OpenAPI::from_slice(OPENAPI)
61        };
62
63        let db = Db::setup(&config.database_url).await.unwrap();
64
65        AppState::new_with(db, openapi).await
66    }
67
68    pub async fn new_with(db: Db, openapi: OpenAPI) -> Self {
69        // conformance
70        #[allow(unused_mut)]
71        let mut conformace = Conformance::default();
72        #[cfg(feature = "stac")]
73        conformace.extend(&[
74            "https://api.stacspec.org/v1.0.0-rc.1/core",
75            "https://api.stacspec.org/v1.0.0-rc.1/item-search",
76            "https://api.stacspec.org/v1.0.0-rc.1/collections",
77            "https://api.stacspec.org/v1.0.0-rc.1/ogcapi-features",
78            "https://api.stacspec.org/v1.0.0-rc.1/browseable",
79        ]);
80
81        // drivers
82        let drivers = Drivers {
83            collections: Box::new(db.clone()),
84            #[cfg(feature = "features")]
85            features: Box::new(db.clone()),
86            #[cfg(feature = "edr")]
87            edr: Box::new(db.clone()),
88            #[cfg(feature = "processes")]
89            jobs: Box::new(db.clone()),
90            #[cfg(feature = "styles")]
91            styles: Box::new(db.clone()),
92            #[cfg(feature = "tiles")]
93            tiles: Box::new(db.clone()),
94        };
95
96        AppState {
97            root: Arc::new(RwLock::new(LandingPage::new("root").description("root"))),
98            conformance: Arc::new(RwLock::new(conformace)),
99            openapi,
100            drivers: Arc::new(drivers),
101            db,
102            #[cfg(feature = "stac")]
103            s3: ogcapi_drivers::s3::S3::new().await,
104            #[cfg(feature = "processes")]
105            processors: Default::default(),
106        }
107    }
108
109    pub fn root(mut self, root: LandingPage) -> Self {
110        self.root = Arc::new(RwLock::new(root));
111        self
112    }
113
114    pub fn openapi(mut self, openapi: OpenAPI) -> Self {
115        self.openapi = openapi;
116        self
117    }
118
119    #[cfg(feature = "stac")]
120    pub async fn s3_client(mut self, client: ogcapi_drivers::s3::S3) -> Self {
121        self.s3 = client;
122        self
123    }
124
125    #[cfg(feature = "processes")]
126    pub fn processors(self, processors: Vec<Box<dyn Processor>>) -> Self {
127        for p in processors {
128            self.processors
129                .write()
130                .unwrap()
131                .insert(p.id().to_string(), p);
132        }
133        self
134    }
135}