Skip to main content

doido_view/
tera_engine.rs

1use crate::engine::TemplateEngine;
2use doido_core::{anyhow::Context as _, Result};
3use std::sync::RwLock;
4
5pub struct TeraEngine {
6    tera: RwLock<tera::Tera>,
7    templates_dir: String,
8}
9
10impl TeraEngine {
11    pub fn new(templates_dir: &str) -> Result<Self> {
12        let pattern = format!("{}/**/*.tera", templates_dir);
13        let tera = tera::Tera::new(&pattern)
14            .with_context(|| format!("failed to load templates from {templates_dir}"))?;
15        Ok(Self {
16            tera: RwLock::new(tera),
17            templates_dir: templates_dir.to_string(),
18        })
19    }
20}
21
22impl TemplateEngine for TeraEngine {
23    fn render(&self, template: &str, context: &serde_json::Value) -> Result<String> {
24        let template_name = format!("{}.html.tera", template);
25        let ctx = tera::Context::from_value(context.clone())
26            .map_err(|e| doido_core::anyhow::anyhow!("invalid template context: {e}"))?;
27        self.tera
28            .read()
29            .unwrap()
30            .render(&template_name, &ctx)
31            .map_err(|e| doido_core::anyhow::anyhow!("template '{}' render failed: {e}", template))
32    }
33
34    fn reload(&self) -> Result<()> {
35        let pattern = format!("{}/**/*.tera", self.templates_dir);
36        let tera = tera::Tera::new(&pattern)
37            .with_context(|| format!("reload failed for {}", self.templates_dir))?;
38        *self.tera.write().unwrap() = tera;
39        Ok(())
40    }
41}