bbox_map_server/
service.rs1use crate::config::MapServiceCfg;
2use crate::fcgi_process::FcgiDispatcher;
3use crate::inventory::Inventory;
4use crate::metrics::{register_metrics, wms_metrics, WmsMetrics};
5use crate::wms_fcgi_backend::detect_backends;
6use actix_web::web;
7use async_trait::async_trait;
8use bbox_core::cli::{NoArgs, NoCommands};
9use bbox_core::config::CoreServiceCfg;
10use bbox_core::service::OgcApiService;
11use log::error;
12use prometheus::Registry;
13use std::collections::HashMap;
14
15#[derive(Clone)]
16pub struct MapService {
17 pub(crate) fcgi_clients: Vec<web::Data<FcgiDispatcher>>,
19 #[allow(dead_code)]
21 suffix_fcgi: HashMap<String, usize>,
22 pub(crate) num_fcgi_processes: usize,
24 pub default_project: Option<String>,
25 pub(crate) inventory: Inventory,
26}
27
28#[async_trait]
29impl OgcApiService for MapService {
30 type Config = MapServiceCfg;
31 type CliCommands = NoCommands;
32 type CliArgs = NoArgs;
33 type Metrics = WmsMetrics;
34
35 async fn create(config: &Self::Config, core_cfg: &CoreServiceCfg) -> Self {
36 let loglevel = core_cfg.loglevel();
37 let num_fcgi_processes = config.num_fcgi_processes();
38 let default_project = config.default_project.clone();
39 let (process_pools, inventory) = detect_backends(config, &loglevel).unwrap();
40 let fcgi_clients = process_pools
41 .iter()
42 .map(|process_pool| web::Data::new(process_pool.client_dispatcher(config)))
43 .collect::<Vec<_>>();
44 let mut suffix_fcgi = HashMap::new();
45 for (poolno, fcgi_pool) in process_pools.iter().enumerate() {
46 for suffix_url in &fcgi_pool.suffixes {
47 suffix_fcgi.insert(suffix_url.suffix.clone(), poolno);
48 }
49 }
50
51 for mut process_pool in process_pools {
52 match process_pool.spawn_processes().await {
53 Ok(_) => {
54 actix_web::rt::spawn(async move {
55 process_pool.watchdog_loop().await;
56 });
57 }
58 Err(e) => {
59 error!("Spawn error: {e}");
60 }
61 }
62 }
63 tokio::time::sleep(std::time::Duration::from_secs(2)).await;
65
66 MapService {
67 fcgi_clients,
68 suffix_fcgi,
69 num_fcgi_processes,
70 default_project,
71 inventory,
72 }
73 }
74 fn conformance_classes(&self) -> Vec<String> {
75 vec![
76 "http://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/core".to_string(),
78 "http://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/png".to_string(),
108 "http://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/jpeg".to_string(),
110 "http://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/tiff".to_string(),
112 "http://www.opengis.net/spec/ogcapi-maps-1/1.0/conf/oas30".to_string(),
120 ]
121 }
122 fn openapi_yaml(&self) -> Option<&str> {
123 Some(include_str!("openapi.yaml"))
124 }
125 fn add_metrics(&self, prometheus: &Registry) {
126 register_metrics(prometheus, self.metrics());
127 }
128 fn metrics(&self) -> &'static Self::Metrics {
129 wms_metrics(self.num_fcgi_processes)
130 }
131}
132
133impl MapService {
134 #[allow(dead_code)]
135 pub fn fcgi_dispatcher(&self, suffix: &str) -> Option<&FcgiDispatcher> {
136 self.suffix_fcgi
137 .get(suffix)
138 .map(|no| self.fcgi_clients[*no].get_ref())
139 }
140}