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#[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
35pub 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 #[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 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}