doido_view/
tera_engine.rs1use 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}