Skip to main content

bbox_asset_server/
endpoints.rs

1use crate::config::AssetServiceCfg;
2use crate::qgis_plugins::*;
3use crate::runtime_templates::RuntimeTemplates;
4use crate::service::{AssetService, PluginIndex};
5use actix_files::{Files, NamedFile};
6use actix_web::{web, HttpRequest, HttpResponse, Result};
7use bbox_core::config::app_dir;
8use bbox_core::endpoints::{abs_req_baseurl, req_parent_path};
9use bbox_core::service::ServiceEndpoints;
10use log::{info, warn};
11use minijinja::context;
12use std::io::Write;
13use std::path::Path;
14use tempfile::tempfile;
15
16async fn templates(
17    envs: web::Data<RuntimeTemplates>,
18    template: web::Path<(String, String)>,
19    req: HttpRequest,
20) -> Result<HttpResponse, actix_web::Error> {
21    let path = Path::new(req.path())
22        .parent()
23        .expect("invalid req.path")
24        .parent()
25        .expect("invalid req.path")
26        .to_str()
27        .expect("invalid req.path")
28        .to_string();
29    let (stem, param) = template.into_inner();
30    let name = format!("{stem}.html");
31    let env = envs.get(&path).unwrap();
32    let tmpl = env.get_template(&name).unwrap();
33    let out = tmpl
34        .render(context!(param => param))
35        .expect("Template render failed");
36    Ok(HttpResponse::Ok().content_type("text/html").body(out))
37}
38
39async fn plugin_xml(plugins_index: web::Data<PluginIndex>, req: HttpRequest) -> Result<NamedFile> {
40    // http://localhost:8080/qgis/plugins.xml -> http://localhost:8080/plugins/qgis/
41    let url = format!("{}/plugins{}", abs_req_baseurl(&req), req_parent_path(&req));
42    let zips = plugins_index
43        .get(req.path())
44        .expect("zip file list missing");
45    let plugins = plugin_metadata(zips);
46    let xml = render_plugin_xml(&plugins, &url);
47    let mut file = tempfile()?;
48    file.write_all(xml.as_bytes())?;
49    Ok(NamedFile::from_file(file, "plugin.xml")?)
50}
51
52impl ServiceEndpoints for AssetService {
53    fn register_endpoints(&self, cfg: &mut web::ServiceConfig) {
54        let service_cfg = AssetServiceCfg::from_config();
55
56        for static_dir in &service_cfg.static_ {
57            let dir = app_dir(&static_dir.dir);
58            if dir.is_dir() {
59                info!(
60                    "Serving static files from directory '{}' on '{}'",
61                    dir.display(),
62                    &static_dir.path
63                );
64                cfg.service(Files::new(&static_dir.path, &dir));
65            } else {
66                warn!("Static file directory '{}' not found", dir.display(),);
67            }
68        }
69
70        let mut template_envs = RuntimeTemplates::default();
71        for template_dir in &service_cfg.template {
72            let dir = app_dir(&template_dir.dir).to_string_lossy().to_string();
73            if Path::new(&dir).is_dir() {
74                let dest = &template_dir.path;
75                info!("Serving template files from directory '{dir}' on '{dest}'");
76                template_envs.add(&dir, dest);
77                cfg.route(
78                    &format!("{dest}/{{name}}/{{param}}"),
79                    web::get().to(templates),
80                );
81            } else {
82                warn!("Template file directory '{dir}' not found");
83            }
84        }
85        cfg.app_data(web::Data::new(template_envs));
86
87        cfg.app_data(web::Data::new(self.plugins_index.clone()));
88
89        for repo in &service_cfg.repo {
90            let dir = app_dir(&repo.dir);
91            if dir.is_dir() {
92                let xmldir = format!("{}/plugins.xml", repo.path);
93                info!(
94                    "Serving QGIS plugin repository from directory '{}' on '{xmldir}'",
95                    dir.display()
96                );
97                cfg.service(Files::new(
98                    &format!("{}/static", repo.path),
99                    app_dir("bbox-asset-server/src/static"), // TODO: RustEmbed !
100                ))
101                .route(&xmldir, web::get().to(plugin_xml))
102                // TODO: same prefix not possible?
103                .service(Files::new(&format!("/plugins{}", repo.path), &dir));
104            } else {
105                // warn!("QGIS plugin repository file directory '{dir}' not found");
106            }
107        }
108    }
109}