catapulte_engine/loader/
local.rs1use super::prelude::Template;
2use serde::Deserialize;
3use serde_json::Value as JsonValue;
4use std::fs::{read_to_string, File};
5use std::io::BufReader;
6use std::path::PathBuf;
7
8#[derive(Clone, Debug, serde::Deserialize)]
9pub struct Config {
10 pub path: PathBuf,
11}
12
13impl Default for Config {
14 fn default() -> Self {
15 Self {
16 path: PathBuf::new().join("template"),
17 }
18 }
19}
20
21impl From<Config> for LocalLoader {
22 fn from(value: Config) -> Self {
23 Self::new(value.path)
24 }
25}
26
27fn default_template_path() -> String {
28 "template.mjml".into()
29}
30
31#[derive(Debug, Deserialize)]
32pub struct LocalMetadata {
33 name: String,
34 description: String,
35 #[serde(default = "default_template_path")]
36 template: String,
37 attributes: JsonValue,
38}
39
40#[derive(Debug, thiserror::Error)]
41pub enum Error {
42 #[error("Unable to open metadata file: {0:?}")]
43 MetadataOpenFailed(std::io::Error),
44 #[error("Unable to deserialize metadata file: {0:?}")]
45 MetadataFormatInvalid(serde_json::Error),
46 #[error("Unable to open template file: {0:?}")]
47 TemplateOpenFailed(std::io::Error),
48}
49
50#[derive(Debug)]
51pub struct LocalLoader {
52 root: PathBuf,
53}
54
55impl LocalLoader {
56 pub fn new(root: PathBuf) -> Self {
57 Self { root }
58 }
59}
60
61impl LocalLoader {
62 pub(super) async fn find_by_name(&self, name: &str) -> Result<Template, Error> {
63 tracing::debug!("loading template {}", name);
64 let path = self.root.join(name).join("metadata.json");
65 let metadata_file = File::open(path).map_err(|err| {
66 metrics::counter!("template_provider_error", "reason" => "metadata_not_found")
67 .increment(1);
68 tracing::debug!("template provider error: metadata not found ({:?})", err);
69 Error::MetadataOpenFailed(err)
70 })?;
71 let metadata_reader = BufReader::new(metadata_file);
72 let metadata: LocalMetadata = serde_json::from_reader(metadata_reader).map_err(|err| {
73 metrics::counter!("template_provider_error", "reason" => "metadata_invalid")
74 .increment(1);
75 tracing::debug!("template provider error: metadata invalid ({:?})", err);
76 Error::MetadataFormatInvalid(err)
77 })?;
78 let template_path = self.root.join(name).join(metadata.template);
79 let content = read_to_string(template_path).map_err(|err| {
80 metrics::counter!("template_provider_error", "reason" => "template_not_found")
81 .increment(1);
82 tracing::debug!("template provider error: template not found ({:?})", err);
83 Error::TemplateOpenFailed(err)
84 })?;
85 Ok(Template {
86 name: metadata.name,
87 description: metadata.description,
88 content,
89 attributes: metadata.attributes,
90 })
91 }
92}