tower_web/view/
handlebars.rs1use response::{Serializer, SerializerContext, ContentType};
2
3use bytes::Bytes;
4use handlebars::Handlebars as Registry;
5use http::header::HeaderValue;
6use http::status::StatusCode;
7use serde::Serialize;
8
9use std::env;
10use std::path::{Path, MAIN_SEPARATOR};
11use std::sync::Arc;
12
13#[derive(Clone, Debug)]
19pub struct Handlebars {
20 registry: Arc<Registry>,
21 html: HeaderValue,
22}
23
24const TEXT_HTML: &str = "text/html";
25
26impl Handlebars {
27 pub fn new() -> Handlebars {
45 let mut registry = Registry::new();
46
47 let mut registered = false;
48
49 if let Ok(value) = env::var("TOWER_WEB_TEMPLATE_DIR") {
51 let base_dir = Path::new(&value);
52
53 if !base_dir.exists() {
54 panic!("TOWER_WEB_TEMPLATE_DIR was set but {:?} does not exist", base_dir);
55 }
56
57 let template_dir = base_dir.join("templates");
58
59 if !template_dir.exists() {
60 panic!("TOWER_WEB_TEMPLATE_DIR was set but the template directory {:?} does not exist", template_dir);
61 }
62 registry.register_templates_directory(".hbs", template_dir).unwrap();
63 registered = true;
64 }
65 if !registered {
66 if let Ok(value) = env::var("CARGO_MANIFEST_DIR") {
68 let dir = Path::new(&value).join("templates");
69
70 if dir.exists() {
71 registry.register_templates_directory(".hbs", dir).unwrap();
72 registered = true;
73 }
74 }
75 }
76 if !registered {
77 let dir = Path::new("templates");
79 if dir.exists() {
80 registry.register_templates_directory(".hbs", dir).unwrap();
81 registered = true;
82 }
83 }
84
85 if !registered {
86 let pwd = Path::new(&env::current_dir().unwrap()).join("templates");
87 panic!("A templates directory was not found. Registering Handlebars failed. Checked at $TOWER_WEB_TEMPLATE_DIR{}templates, $CARGO_MANIFEST_DIR{}templates (crate root), and {:?} (under the current working directory).", MAIN_SEPARATOR, MAIN_SEPARATOR, pwd);
88 }
89
90 Handlebars::new_with_registry(registry)
91 }
92
93 pub fn new_with_registry(registry: Registry) -> Handlebars {
98 Handlebars {
99 registry: Arc::new(registry),
100 html: HeaderValue::from_static(TEXT_HTML),
101 }
102 }
103}
104
105impl Serializer for Handlebars {
106 type Format = ();
107
108 fn lookup(&self, name: &str) -> Option<ContentType<Self::Format>> {
109 match name {
110 "html" | TEXT_HTML => {
111 Some(ContentType::new(self.html.clone(), ()))
112 }
113 _ => None,
114 }
115 }
116
117 fn serialize<T>(&self, value: &T, _: &Self::Format, context: &SerializerContext)
118 -> Result<Bytes, ::Error>
119 where
120 T: Serialize
121 {
122 if let Some(template) = context.template() {
123 match self.registry.render(template, value) {
124 Ok(rendered) => {
125 return Ok(rendered.into());
126 }
127 Err(err) => {
128 error!("error rendering template; err={:?}", err);
129 return Err(::Error::from(StatusCode::INTERNAL_SERVER_ERROR))
130 }
131 }
132 }
133
134 error!("no template specified; {}::{}::{}",
137 context.resource_mod().unwrap_or("???"),
138 context.resource_name().unwrap_or("???"),
139 context.handler_name().unwrap_or("???"));
140 Err(::error::Error::from(StatusCode::INTERNAL_SERVER_ERROR))
141 }
142}
143
144impl ::util::Sealed for Handlebars {}